UPD on 2020.4.1:
感谢 OItby
神仙指出错误,已更正。欢迎别的神仙来指教 & 吊打本萌新
首先我们要用到一些均分纸牌的思想(已经理解这种思想的大佬请跳过):
设(A_i)表示第(i)个小朋友原有的糖果数量,
设(ave)表示所有小朋友糖果数量的平均数,
(X_i)表示第(i)个小朋友向左传的糖果数量。即:
①如果(X_i>0:quad) 第(i)个小朋友向左传(X_i)个糖果;
②否则如果(X_i<0:quad) 第(i)个小朋友向左传(|X_i|)个糖果。
所以该题的代码为:
Code:
#include<cstdio>
int a[101];
int n,x,s;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
x+=a[i];
}
x/=n;
for(int i=1;i<n;++i)
{
a[i]-=x;
if(a[i]!=0)
{
++s;
a[i+1]+=a[i];
}
}
printf("%d",s);
return 0;
}
好现在让我们回到原题糖果传递上来。
看看刚刚设的什么:
设(A_i)表示第(i)个小朋友原有的糖果数量,
(ave)表示所有小朋友糖果数量的平均数,
(X_i)表示第(i)个小朋友向左传的糖果数量。
则由题可得方程:
即:
[A_i+X_{i+1}-X_i=ave(1le i<n) ]
[A_n+X_1-X_n=ave(i=n) ]
变形得:
这时我们设:
即设:
[C_i=sum_{j=1}^iA_j-i·ave(1le ile n) ]
则有:
即:
[X_i=X_1-C_i ]
这时我们返回来看所求,要求传递价值最小,
这就是说,要求最小化
而该式等于
即求:
[MIN { sum_{i=1}^nX_i }=MIN { sum_{i=1}^nX_1-C_i } ]
这样就好办了,(C_i)是已知(额,至少是可以预处理出来)的,要想最小化上式,我们把(C_i)看成数轴上的一个个点,现在问题就转化成了找出一个点(X_1),使得她到各个(C_i)上的点的距离和最小。
而这个点就是这(n)个点的中位数,后面有证明qwq
那么求出了(X_1)之后,根据
这一坨柿子,我们可以求出(X_2,X_3…X_n),然后就可以偷税的得到所求的:
最小化
啦233~~~
代码好丑,大家别嫌弃qwq:
Code:
#include<bits/stdc++.h>
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define inline il
typedef long long ll;
typedef long double ld;
const int inf = 0x7fffffff;
const int N = 1e6+1;
ll n;
ll a[N],c[N];
ll ave,ans,mid;
using namespace std;
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]),ave+=a[i];
ave/=n;
for(int i=1;i<=n;++i)
c[i]=c[i-1]+ave-a[i-1];
sort(c+1,c+n+1);
mid=c[(n+1)/2];
for(int i=1;i<=n;++i)
ans+=abs(mid-c[i]);
printf("%lld",ans);
return 0;
}
附:数学证明
在数轴上有(n)个点,找出一个点(x),使得她到各个点的距离和最小。
求证:该点表示的数就是这(n)个数的中位数。
如果我们把数轴上的点两两配对,最大的配最小的,次大的配次小的……
则到每组点最近的距离的点在这两个点中间,那么
如果有奇数个点,那么显然中间那个点便为所求。
∴该点表示的数是这(n)个数的中位数得证。
注:
有一些柿子在文中以不同的形式重复出现,主要是为了同时满足大佬和蒟蒻的需要。一些前面写了‘即…’并用
这个东西
框起来的一般是适合大佬的较严(bian)格(tai)数学写法,而其他的则是简明易懂的正常的、不变态的写法。