[CQOI2011] 分金币
mayike
·
·
题解
题目传送门
没做此题的不要看
题意
有 n 个干草堆组成一个环,在第 i 个位置有 a[i] 个干草堆,可以将任意位置的干草堆向前或向后移动若干个,使第 i 个位置有 ans 个干草堆,询问最少需要移动多少个干草堆。
思路
实则就是均分纸牌的升级版,其贪心思想也是本题要用到的。
即可规定一个方向,这里我规定向左,每堆牌都向左传,变成 ans 个,若本不足 b[i] 个咋办呢,那就向左索要,其实等价于传负数个,详细看这位大佬的 blog。
注:以上链接博客均非本人所有
那么我们可设每个位置原有 a[i] 个,要变成 ans 个,向左传递(左右都可以,单一方向即可,这里规定向左)x[i] 个。
则所求值为 \sum _ {i = 1}^n\min(| x[i] |)。
由题意我们可知:
ans=a[1]+x[2]-x[1]
ans=a[2]+x[3]-x[2]
依次推得当 1 \le i < n 时:
ans=a[i]+x[i+1]-x[i]
ans=a[n]+x[1]-x[n]
可得:
x[2]=ans+x[1]-a[1]
x[3]=ans+x[2]-a[2]=ans+(ans+x[1]-a[1])-a[2]
ans+(ans+x[1]-a[1])-a[2]=2 \times ans-a[1]-a[2]+x[1]
即:
x[3]=2 \times ans-a[1]-a[2]+x[1]
对于 2 \le i \le n 有:
x[i]=\sum_{j=1}^{i-1}(ans-a[j]) + x[1]
x[1]=\sum_{j=1}^{n}(ans-a[j]) + x[1]
不妨设:
c[1]=a[1]-ans
c[2]=a[1]+a[2]-2 \times ans
对于 1 \le i \le n 则有:
c[i]=\sum_{j=1}^{i}(a[j]-ans)
即可知道:
x[2]=x[1]-c[1]
x[3]=x[1]-c[2]
当 2 \le i \le n 时:
x[i]=x[1]-c[i-1]
x[1]=x[1]-c[n]
所以:
\sum _ {i = 1}^n\min(| x[i] |)
等价于:
\sum _ {i = 1}^n\min(| x[1]-c[i] |)
放在数轴上来讲就是点 x[1] 到 c[i] 的距离和的最小值,此处 1 \le i \le n。
那么 x[1]=c[\frac{n+1}{2}] 时就一定可取最小值,这个就不说明了,自己思考一下为什么。
对于 1 \le i \le n,c[i] 我们是已知的。那么,本题完。
等等,还有代码!
代码
#include<bits/stdc++.h>
using namespace std;
long long n,a[1000001],c[1000001],sum,mid,ans;
int main(){
//经验: p2512 UVA11300 p3051 p4016 p2125 p5817 SP11117
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];
sum/=n;
for(int i=1;i<=n;i++)c[i]=c[i-1]+a[i]-sum;
sort(c+1,c+1+n);mid=c[(n+1)/2];
for(int i=1;i<=n;i++)ans+=abs(mid-c[i]);
cout<<ans;
}