P2512 [HAOI2008] 糖果传递
P2512 [HAOI2008] 糖果传递
方法一:
费用流,过不了
方法二:
不难发现,传递路线不会交叉,所以如果题目不是环,是序列的情况下,可以直接
考虑破环,枚举
显然会超时,不难发现是单峰函数,三分即可,时间复杂度为
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+50,inf=2e9;
int n,a[N],b[N],ans=1e18,to;
int work(int x){
int tot=abs(x);
for(int i=1;i<=n;i++) b[i]=a[i];
b[n]+=x; b[1]-=x;
for(int i=1;i<n;i++){
if(b[i]<to) tot+=to-b[i],b[i+1]-=to-b[i];
else tot+=b[i]-to,b[i+1]+=b[i]-to;
}
return tot;
}
main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),to+=a[i];
to/=n;
int L=-inf,R=inf;
while(L+3<=R){
int x=L+(R-L)/3,y=L+(R-L)*2/3;
if(work(x)<work(y)) R=y-1;
else L=x;
}
for(int i=L;i<=R;i++) ans=min(ans,work(i));
printf("%lld\n",ans);
}
方法三:
设
那么有
设
答案为
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+50;
int n,a[N],to,c[N],ans;
main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),to+=a[i];
to/=n;
for(int i=2;i<=n;i++) c[i]=c[i-1]+a[i-1]-to;
sort(c+1,c+n+1);
int x=-c[(n+1)/2];
for(int i=1;i<=n;i++) ans+=abs(x+c[i]);
printf("%lld\n",ans);
}