题目描述
图书馆有n个书架,第1个书架后面是第2个书架,第2个书架后面是第3个书架……第n-1个书架后面是第n个书架,第n个书架后面是第1个书架,第i个书架上有b[i]本书。现在,为了让图书馆更美观,WZF神牛让蒟蒻SY搬动书架上的书,使每个书架上的书一样多。由于搬动的书可能会很多,所以蒟蒻SY只能将一个书架上的书搬到与其相邻的两个书架上。那么蒟蒻SY最少搬动几本书呢?
输入输出格式
输入格式:共2行,第1行1个正整数n,第2行n个非负整数,第i个为b[i]。
输出格式:共n+1行,第1行1个正整数m,表示蒟蒻SY最少搬动m本书,之后n行(即第2行至第n+1行)每行2个整数,第i行有两个整数af[i]和ab[i],分别表示蒟蒻SY要将第i个书架上的af[i]本书和ab[i]本书分别搬到它前面的一个书架上和它后面的一个书架上。
输入输出样例
5 15 7 11 3 14
12 2 3 -3 0 0 1 -1 -6 6 -2
说明
n<=5000001(为保证有唯一解,n必为奇数),b[i]<= 21474803648(蒟蒻SY:俺当初一看到这儿就想哭。)
若af[i]为负数,则说明蒟蒻SY要把第i个书架前面的那个书架上的-af[i]本书搬到第i个书架上。
同理,若ab[i]为负数,则说明蒟蒻SY要把第i个书架后面的那个书架上的-ab[i]本书搬到第i个书架上。
题解
有N个书架, x1---->x2---->x3---->x4---> ... ----->xn ----->x1
依次给下一层数量 a1 a2 a3 a4 ... an
每个x先减去平均值: xn -= p;
则有
{
x1+an-a1=0;
x2+a1-a2=0;
........
xn+an-1-an=0;
}
ANS=|a1|+...+|an|
ANS=|a1|+|a1+x2|+|a1+x2+x3|+...
因为n为奇数,当a1取0,x2,x2+x3,...这些点中点即为最小解
代码
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
#define For(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
const int maxx=5000010;
ll a[maxx],sum[maxx],tmp[maxx],p,ans,flag;
ll read(){
char x;
while((x=getchar())<'0' || x>'9');
ll u=x-'0';
while((x=getchar())>='0' && x<='9') u=u*10+x-'0';
return u;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
freopen("output.out","w",stdout);
#endif
int i,j,k,m,n;
n=read();
For(i,1,n){
a[i]=read();
sum[0]+=a[i];
}
p=sum[0]/n;
a[1]-=p;
For(i,2,n) { a[i]-=p; sum[i]=sum[i-1]+a[i]; tmp[i]=sum[i];}
sort(tmp+1,tmp+n+1);
flag=-tmp[n/2+1];
For(i,1,n) ans+=abs(flag+sum[i]);
printf("%lld\n",ans);
printf("%lld %lld\n",-(sum[n]+flag),flag);
For(i,2,n)
printf("%lld %lld\n",-(sum[i-1]+flag),sum[i]+flag);
return 0;
}