链接:https://uva.onlinejudge.org/index.php?///option=com_onlinejudge&Itemid=8&pa
ge=show_problem&problem=2275
刚开始看到这题目,我是没什么想法的,没想到书上的技巧看起来如此的简单
假设M为每个人都拥有的金币数,每个人的金币变化是左右相邻的人对其造成的影响
假设这n个人构成一个环,先假设n=4,设x1指1号给4号多少金币,则x2代表2号给1号
多少金币,其他的由此类推下去。
则对于1号来说,他给了4号金币,则剩a1-x1
2号给了他金币,则剩a1-x1+x2
注意这里1号给4号和4号给1号的意义隐含在x1的符号里面(很巧妙),其他的类似
由于最后要等于M,然后就可以得方程了
a1-x1+x2=M >> x2 = x1-(a1-M) = x1 - C1
a2-x2+x3=M >> x3 = x2-(a2-M)=x1-a1-a2-2*M = x1 - C2
a3-x3+x4=M >> x4 = x3-a1-a2-a3-3*M = x1 - C3
an-xn+x1=M >> xn = x1 - C(n-1)
看到这里我们知道答案是所有xi的绝对值最小了
很显然这就转化为数轴上求一点x到ci距离和的最小值,然而这个点x其实就是序列ci(排
序后)的中位数,稍微想想应该知道
中位数可以用到许多此模型的题上
看起来那么复杂,最后却如此简单,数学的强大力量
代码如下:
1 #include<cstdio> 2 #include<math.h> 3 #include<vector> 4 #include<algorithm> 5 #define LL long long 6 using namespace std; 7 8 const int maxn = 1e6+10; 9 LL c[maxn]; 10 int main() 11 { 12 int n; 13 LL a,sum,M; 14 while(scanf("%d",&n)==1) 15 { 16 sum = 0; 17 c[0] = 0; 18 for(int i = 1; i<=n; i++) 19 { 20 scanf("%lld",&a); 21 c[i] = c[i-1] + a; 22 sum += a; 23 } 24 M = sum / n; 25 for(int i = 1; i<n; i++) c[i] -= i*M; 26 sort(c,c + n); 27 LL x1 = c[n/2] , ans = 0; 28 for(int i = 0; i<n; i++) ans += abs(x1-c[i]); 29 printf("%lld\n",ans); 30 31 } 32 return 0;
时间: 2024-10-01 04:51:23