当前位置: 代码迷 >> 综合 >> [HAOI2008]糖果传递(个人对题目的分析)
  详细解决方案

[HAOI2008]糖果传递(个人对题目的分析)

热度:27   发布时间:2023-12-03 16:48:12.0

这题与其说是贪心,我觉得不如说是数学来着,整个人没看到其他大佬的解法之前是一脸懵逼的,打表也打不出规律啥也整不出来。。。。鉴于本人能力有限于是去参考其他大佬的解法得到了自己简单的想法。。。

首先,我们先明确我们要求的答案是什么,是要求最小的操作数,那这个操作数的话就是所有n个相邻两个传递的糖果数,因为两面传太烦了,所以我们规定只能左边传右边,为什么可以只规定一边呢,因为和矢量差不多,我们可以规定传递了负数个嘛。

我们需要找到一个地方开始传,但我们又不知道哪里可以开始传,那我们索性就假设某一点开始传,然后我们设相邻之间的传递值是x1,x2,x3...直到xn-1

我们设所有数的平均值是u,那么我们可以得到以下公式:

X1=A1-u+Xn

X2=A2-u+X1=A2+A1-u*2+Xn

X3=A3-u+X2=A3+A2+A1-u*3+Xn

...

以此类推

\sum_{i=1}^{n-1}(Ai-u)+Xn= C[n-1],那么我们要的解其实就是|C[1]+Xn|+|C[2]+Xn|+.......+|C[n-1]+Xn|,我们仔细想想,这些数字难道不是可以直接化为对0坐标的相对距离吗(其实Xn本身就是0,因为我们断链了,左边不会传东西过来,因为传到最后一个刚刚好等于平均数)

那么不就演变成了我们从这些点中间寻找一点能找到它们的距离之和最小吗。至于为什么把0加进去呢,因为0是起点啊,这些距离全都是根据0的距离。

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
long long int a[2000005];
long long b[1000005];
int main(){int n;cin>>n;long long res=0;for(int i=1;i<=n;i++){cin>>a[i];res+=a[i];}res/=n;for(int i=1;i<=n-1;i++){a[i]=a[i]+a[i-1]-res;}int t=0;for(int i=0;i<=n-1;i++){b[++t]=a[i];//这些是新建数轴的坐标}sort(b+1,b+1+t);long long cnt=0;//接下来就是为这t个点找某一点加起来聚合的最近点啦。那肯定是中位点for(int i=1;i<=t;i++){cnt+=abs(b[i]-b[(t+1)/2]);}cout<<cnt;
}