题目描述
原题来自:HAOI 2008
有 n个小朋友坐成一圈,每人有 ai 颗糖果。每人只能给左右两人传递糖果。每人每次传递一颗糖果的代价为 1 。求使所有人获得均等糖果的最小代价。
输入格式
第一行有一个整数 ,n表示小朋友个数;
在接下来 n行中,每行一个整数 。
输出格式
输出使所有人获得均等糖果的最小代价。
样例
样例输入
4
1
2
5
4
样例输出
4
数据范围与提示
对于 30% 的数据,n<1000;
对于100% 的数据,n<10^9,保证答案可以用64 位有符号整数存储。
题目链接:https://loj.ac/problem/10010
对于这道,emmmm据说是小学奥赛题,我看博客半小时才弄通,最后发现是自家会长的博客,O(∩_∩)O哈哈~
跪拜大佬:https://blog.csdn.net/qq_41890797/article/details/90244567
我对这道数学题的思路:
1.设未知数; 2.求公式;3.求中位数的负数;^_^ha大废话,显然觉的这道题有很多值得深入挖掘的性质,比如每个人最终的状态求个平均值就好了 。那么先不考虑算法(好像也不涉及算法),而是研究一波题面。
1.显然,代价的计算是一个麻烦的事情。我认为代价的计算应该是与路径有关,而不是与人有关。也就是说,我们关心的是两个人之间的路径上糖果移动的情况,可以设Xi:Ai—>Ai+1为糖果的路径转移。
2.我又发现,一条路径上糖果的移动方向只有一个,可以用正负来表示。接着我们还发现,只要知道了一条路径上糖果的移动情况,那么其他路径也是可以推出来的。
这时,公式已经出来了,也就是求出平均数然后列出每一条路径的糖果运送情况得到的,得到固定值Si的中位数,让Xn为中位数的相反数即可;
每人每次传递一个糖果代价为1
推公式过程
本题用到递推和贪心的算法思想,偏重对数学思维的检测。
(1).需要注意的题中条件:
<1>.首先要明确:n个人围成环坐;
<2>.只能左右传递;
<3>.使得每个人得到均等的饺子ave;
(2).找出递推式
<1>关注的每两个人之间的路径上饺子移动的情况。
<2> 设第i个人会给第i+1个人xi个糖果(带符号)即下图:那么 ai-xi+xi-1=ave;
1 2 3 4
初始值: 1 2 5 4
最终值: 3 3 3 3
移动情况:-2 -1 2 1
<3>将所有的式子列出来然后每一个做一个前缀和:那么xn−xi=∑ai−ave。
<5> 变形:xi=xn−(∑ai−ave)。((∑ai−ave)为一个常量,简写为k)
<4>找到递推式,要求∑|xi|最小实际上就是要求∑|xn−k|最小 。利用绝对值的几何意义,那么xn取这些常量k里的中位数时,愤怒值有最小值.
上代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int M=1e6+10;
int a[M],s[M];
int main()
{int n;ll sum=0;scanf("%d",&n);for(int i=1; i<=n; i++){scanf("%d",&a[i]);sum+=a[i];}ll ave=sum/n,ans=0;for(int i=1; i<=n; i++)s[i]=(a[i]-ave)+s[i-1];///减平均值后的前缀和sort(s+1,s+1+n);///为求中位数for(int i=1; i<=n; i++)ans+=abs(s[i]+(-s[(n+1)>>1]));///找(s[(n+1)>>1]为中位数)的负数printf("%lld\n",ans);return 0;
}