洛谷 P2512 [HAOI2008]糖果传递

题目描述
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
输入输出格式
输入格式:

小朋友个数n,下面n行 ai

输出格式:

求使所有人获得均等糖果的最小代价。

输入输出样例
输入样例#1:
4
1
2
5
4
输出样例#1:
4
说明:
对于100%数据,n <= 10^6

这是一道环形均分纸牌问题,可以枚举每个小朋友作为起点,再进行一波像均分纸牌那样的操作,就可以得出最小值
但是这道题的数据范围是10^6,这种操作复杂度是O(n^2),会超时的。
(我试了一下,bug死活de不过去了。正解是4,我的一直在固执地输出6…)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[100003],b[10003];
int ans = 0,sum = 100000;
//先把它放在这里,等有时间了还是再de一下地比较好
int main()
{
    int n;
    scanf("%d",&n);
    int s = 0;
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&a[i]);
        s += a[i];
    }
    s = s / n;
    for(int i = 1;i <= n;i++)
    {
        a[i] -= s; 
    }
    for(int i = n + 1;i <= 2 * n;i++)
    {
        a[i] = a[i - n];
        b[i - n] = a[i];
    }
    for(int i = 1;i <= n;i++)
    {
        for(int j = i;j <= i + n - 1;j++)
        {
            if(a[j] == 0)continue;
            a[j + 1] += a[j];
            ans += abs(a[j]);
            a[j] = 0;
        }
        for(int j = 1;j <= n;j++)
        {
            a[j] = b[j];
            a[j + n] = a[j];
        } 
        sum = min(ans,sum);
    }
    printf("%d",sum);
    return 0;
}

然后我在网上找到了一位大佬的题解
易得:
x1=x1-0;
X2=ave-A1+X1=X1-C1 (C1=A1-ave)
X3=2ave-A1-A2+X1+X2=X1-C2 (C2=A1+A2-X2-2ave)
X4=3ave-A1-A2-A3+X1+X2+X3=X1-C3
(C3=A1+A2+A3-X2-X3-3ave)
其中ci可在O(n)时间内预处理出来. ……..
ans=|x1|+|x1-c1|+…..|x1-cn-1|.
也就是等于这个东西∑i=1∣S[i]−S[k]∣的最小值
M
(这里s[ i ]表示第 i 点的前缀和,表示将前面所有的都看做一个小孩子时,他需要这个向整体移动的糖数)
几何意义即为x1距0,c1,…..cn-1距离和最小
x1取中位数即可。
https://www.luogu.org/problemnew/solution/P2512
然后就可以解出来了

但是!但是!出现了一点小问题。
我re了7个点。
然后我把洛谷题解里的标称改了改交上去了,它也re了七个点
我终于ac了
果然一切的re都是因为数组开小了
(我能怎么办,我也很绝望啊)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[100003],sum[100003];
long long ans = 0,s = 0;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&a[i]);
        s += a[i];
    }
    s = s / n;
    for(int i = 1;i <= n;i++)
    {
        a[i] -= s; 
    }
    for(int i = 1;i <= n;i++)
    {
        sum[i] = sum[i - 1] + a[i];
    }
    sort(sum + 1,sum + n + 1);
    for(int i = 1;i <= n;i++)
    {
        ans += abs(sum[(n + 1) / 2] - sum[i]);
    }
    printf("%lld",ans);
    return 0;
}

可能今天不适合写这道题吧……
心好累

猜你喜欢

转载自blog.csdn.net/qq_42914224/article/details/82563382
今日推荐