USACO 重排干草 Haybale Restacking, 2012 Mar
Description
约翰订购了很多干草,他在农场里标记了 N 个位置。这些位置近似地构成一个圆环。他原打算 让送货司机在 i 号位卸下 Bi 捆干草。然而,送货司机搞乱了约翰的部署,胡乱卸货之后就离开了。 约翰数了数,目前在 i 号位有 Ai 捆干草,Ai 的总和是等于 Bi 的,说明司机至少没有少送货。
无奈之下,约翰只能自己来移动这些干草。约翰必须沿相邻位置来移动干草,每移动一捆干草到 一个相邻位置,要消耗约翰一单位的能量。请帮约翰规划一下,他最少消耗多少能量才能让所有位置 的干草数量从 {Ai} 变成 {Bi}?由于是圆环,所以 1 号位和 N 号位也算作是相邻的。
Input Format
• 第一行:单个整数 N ,1 ≤ N ≤ 10^5
• 第二行到 N + 1 行:第 i + 1 行有两个整数:Ai 和 Bi,1 ≤ Ai , Bi ≤ 1000
Output Format
单个整数:表示约翰消耗的最少能量之和
Sample Input
4 7 1 3 4 9 2 1 13
Sample Output
13 解释 将 6 捆干草从 1 号位移到 4 号位,1 捆干草 从 3 号位移到 2 号位,6 捆干草从 3 号位移到 4 号位
solution
设xi为第i堆干草与第i-1堆干草的交换数
令B[i]等于B[i]-A[i],则我们的目标是让B[i]全部变为0
B[1]-x1+x2=0 ==> x2=x1-B[1]
B[2]-x2+x3=0 ==> x3=x2-B[2]=x1-B[1]-B[2]
......xn-1=x1-B[1]-B[2]-...-B[n-1]
而我们要使 x1+x2+x3+...+xn-1 最小, 即|x1|+|x1-B[1]|+...+|x1-B[1]-B[2]-...-B[n-1]| 最小
所以x1要等于B[1],B[1]+B[2],...,B[1]+B[2]+...+B[n-1]的中位数
刘汝佳大神的蓝皮书第4页有道类似的题叫分金币,大佬们有兴趣可以看看
#include<cstdio> #include<algorithm> int N,M,B[100024]; long long Ans; int main() { scanf("%d", &N); M=(N+1)>>1; for(int a,g=1;g<=N;++g) scanf("%d%d", &a,&B[g]),B[g]-=a,B[g]+=B[g-1]; std::sort(B+1,B+N+1); for(int g=1;g<=N;++g) Ans+=1ll*((B[g]>B[M])?B[g]-B[M]:B[M]-B[g]); printf("%lld", Ans); return 0; }