题目来源:AcWing 122.糖果传递
题目描述
有n个小朋友坐成一圈,每人有a[i]个糖果。
每人只能给左右两人传递糖果。
每人每次传递一个糖果代价为1。
求使所有人获得均等糖果的最小代价。
输入描述
第一行输入一个正整数n,表示小朋友的个数。
接下来n行,每行一个整数a[i],表示第i个小朋友初始得到的糖果的颗数。
输出描述
输出一个整数,表示最小代价。
数据范围
1 ≤ n ≤ 1000000,
0 ≤ a[ i ] ≤ 2×109,
数据保证一定有解。
输入样例
4
1
2
5
4
输出样例
4
OP
这道题代码不难,主要是思路,通过数学方法转化问题。
思路
我们假设第 i 名小朋友有 a[ i ] 颗糖,并向其右侧小朋友传递 x[ i ] 颗糖( x[ i ] 为整数,若为负值即说明反向传递)。( x[ n ] 也可以视作 x[ 0 ] )
在这种假设下,我们的所求即为 ∣x[1]∣+∣x[2]∣+...+∣x[n−1]∣+∣x[n]∣ 的最小值。
设传递之后,每名小朋友均有 p 颗糖,我们可以列出如下方程组:
a[1]−x[1]+x[n]=b
a[2]−x[2]+x[1]=b
…
a[n−1]−x[n−1]+x[n]=b
a[n]−x[n]+x[n−1]=b
整理①式,我们可以得出:x[1]=x[n]−b+a[1]
将其代入②式,便可以得出x[2]=x[n]−2∗b+a[1]+a[2]
以此类推:x[i]=x[n]−i∗b+a[1]+a[2]+...+a[i]
此时,我们所求即转化为
∣x[n]−b+a[1]∣+∣x[n]−2∗b+a[1]+a[2]∣+...+∣x[n−1]=x[n]−(n−1)∗b+a[1]+a[2]+...+a[n−1]∣+∣x[n]=x[n]−0∗b+a[1]+a[2]+...+a[n]∣
的最小值。
现在,我们就可以将上式看作另一个问题:
数轴上有一系列点: b+a[1],2∗b+a[1]+a[2],(n−1)∗b+a[1]+a[2]+...+a[n−1],0∗b+a[1]+a[2]+...+a[n] ,求某一点(x[ 0 ])与他们所有点的距离之和最短。
将 x[ 0 ] 放在这一系列点的中位数处显然是最短的,就如货仓选址这道题。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <bits/stdc++.h> using namespace std;
int main() { static long long n,a[1000006]={0},d[1000006],i,p; cin>>n; for(i=1;i<=n;i++){scanf("%lld",&a[i]);d[i]=a[i]+d[i-1];} p=d[n]/n; for(i=1;i<=n;i++) { d[i]-=i*p; } sort(d+1,d+1+n); long long sum=0; for(i=1;i<=n;i++) {sum+=abs(d[i]-d[(n+1)/2]);} printf("%lld",sum); return 0; }
|
ED
y总yyds