[HAOI2008]糖果传递
传送门:https://www.luogu.org/problem/P2512
首先我们可以很自然的想到一道叫做均分纸牌的题(https://www.luogu.org/problem/P1031)在这道题中因为不是环所以就可以直接从第一个开始维护它需要移动的纸牌数然后就依次叠加就好了。
但是本题,就很恶心Orz,它是个环(蒟蒻我个人认为一道本来是链的题,变成换之后就会难很多)好了开始讲这道题的解法。
因为一定可以均分所以用sum统计总和,那么sum/n一定可以被整除。由此可以得到一个鬼畜的想法。
设原数组为a[i] , x[i]表示 i 和 i-1 的交换量(i=1时表示与n的交换量),ave 为平均值
对于第1个小朋友,A1-X1+X2=ave -> X2=ave-A1+X1 = X1-C1(假设C1=A1-ave,下面类似)
对于第2个小朋友,A2-X2+X3=ave -> X3=ave-A2+X2=2ave-A1-A2+X1=X1-C2
对于第3个小朋友,A3-X3+X4=ave -> X4=ave-A3+X3=3ave-A1-A2-A3+X1=X1-C3
…… 对于第n个小朋友,An-Xn+X1=ave。
我们希望Xi的绝对值之和尽量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要尽量小。注意到|X1-Ci|的几何意义是数轴上的点X1到Ci的距离,所以问题变成了:给定数轴上的n个点,找出一个到他们的距离之和尽量小的点,而这个点就是这些数中的中位数
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 int n; 9 int a[1000009]; 10 int b[1000009]; 11 long long sum; 12 long long ans; 13 inline int kd() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 17 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 18 return x*f; 19 } 20 int main() 21 { 22 n=kd(); 23 for(int i=1;i<=n;i++) 24 { 25 a[i]=kd(); 26 sum+=a[i]; 27 } 28 sum/=n; 29 for(int i=1;i<=n;i++) 30 { 31 b[i]=b[i-1]-(a[i]-sum); 32 } 33 sort(b+1,b+1+n); 34 long long mid=b[(n+1)/2]; 35 for(int i=1;i<=n;i++) 36 { 37 ans+=abs(b[i]-mid); 38 } 39 cout<<ans; 40 }