专栏文章
P2512 [HAOI2008] 糖果传递
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min4f08z
- 此快照首次捕获于
- 2025/12/01 20:23 3 个月前
- 此快照最后确认于
- 2025/12/01 20:23 3 个月前
P2512 [HAOI2008] 糖果传递
方法一:
费用流,过不了
方法二:
不难发现,传递路线不会交叉,所以如果题目不是环,是序列的情况下,可以直接 贪心解决
考虑破环,枚举 号点和 号点传递的量,即可变成序列的情况
显然会超时,不难发现是单峰函数,三分即可,时间复杂度为
代码:
CPP#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);
}
方法三:
设 为 号点传递给 号点的个数, 为 给 的
那么有 ,即
设 ,则
答案为 ,排序后让 取中位数即可
代码:
CPP#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);
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...