题目概述
有 n n 个JZ坐成一圈,每人有 个神犇值。每人只能给左右两人传递神犇值。每人每次传递一个神犇值代价为 1 1 。用最少的代价使 个JZ神犇值一样,以便虐人。
解题报告
远古省选题……被各种改题意,貌似已经烂大街了?
假设第
i
i
个人向 传递了
xi
x
i
(负数表示
i+1
i
+
1
向
i
i
传递),令 ,那么:
xn−x1=ave−a1x1−x2=ave−a2⋯xn−1−xn=ave−an
x
n
−
x
1
=
a
v
e
−
a
1
x
1
−
x
2
=
a
v
e
−
a
2
⋯
x
n
−
1
−
x
n
=
a
v
e
−
a
n
令 ci=∑ni=1ave−ai c i = ∑ i = 1 n a v e − a i ,累加后得到:
xn−x1=c1xn−x2=c2⋯xn−xn=cnans=∑i=1n|xi|=∑i=1n|xn−ci|
x
n
−
x
1
=
c
1
x
n
−
x
2
=
c
2
⋯
x
n
−
x
n
=
c
n
a
n
s
=
∑
i
=
1
n
|
x
i
|
=
∑
i
=
1
n
|
x
n
−
c
i
|
也就是说答案转化到了一个变量身上,这就比较好处理了。观察这个式子,我们可以认为这是 xn x n 与 ci c i 的距离之和,最小值在 xn x n 在 {cn} { c n } 的中位数取到。
示例程序
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1000000;
int n,a[maxn+5];LL ave,sum[maxn+5],ans;
#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)
inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF;return *l++;
}
inline int readi(int &x){
int tot=0,f=1;char ch=readc(),lst='+';
while (!isdigit(ch)) {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while (isdigit(ch)) tot=(tot<<3)+(tot<<1)+(ch^48),ch=readc();
return x=tot*f,Eoln(ch);
}
inline LL Abs(LL x) {if (x<0) return -x;return x;}
int main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);for (int i=1;i<=n;i++) readi(a[i]),ave+=a[i];
ave/=n;for (int i=1;i<=n;i++) sum[i]=sum[i-1]+ave-a[i];
sort(sum+1,sum+1+n);LL mid=sum[n+1>>1];
for (int i=1;i<=n;i++) ans+=Abs(sum[i]-mid);
return printf("%lld\n",ans),0;
}