P1031 [NOIP2002 提高组] 均分纸牌

方法一:

简单贪心题。

如果每个数相等时的数为sum,考虑一个数不等于sum,最好的情况通过一次转移使它变为sum。

所以按顺序处理,当前数少从后面拿,当前数多向后面扔,中间记录次数即可。

考虑正确性,有人会觉得,如果后面的数不够拿成为了负数,需要从更后面拿,就不止一次转移了。

其实,如果遇到上述情况,可以先做后面的数从更后面拿数的操作,再做当前数拿数操作,这样操作总数不变。

由此可证,只要不等于sum,拿一次就好了。

复制代码
#include <bits/stdc++.h>
using namespace std;
int n,a[110],sum,ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
    sum/=n;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>sum) ans++,a[i+1]+=a[i]-sum;
        else if(a[i]<sum) ans++,a[i+1]-=(sum-a[i]);
    }
    printf("%d",ans);
    return 0;
}
复制代码

 方法2:

上一个方法够解决这个问题,但考虑如果要输出方案,上面的写法不好实现。

所以要有一点小改进,使每次移动不会出现移动数大于总数的情况。

因为向后扔的操作一定没有这种问题,我们就先处理向后扔的情况,再向前扔。

复制代码
#include<iostream>
#define MAXN 101
using namespace std;
int main()
{
    int n, a[MAXN], sum[MAXN]={0}, d;
    cin >> n;
    for(int i=1; i<=n; i++)
    {
        cin >> a[i];
        sum[i]=sum[i-1]+a[i];
    }
    int ave = sum[n]/n;
    int count=0; 
    for(int i=1; i<=n; i++)
    {
        if(sum[i]>i*ave) //sumstd[i]=i*ave, 向后面均匀一些 
        {
            d = sum[i]-i*ave;
            sum[i] -= d;
            a[i] -= d;//手模或简单思考可证,a[i]此时一定大于等于d.
            a[i+1] += d;
            count++;
        }                    
    }
    for(int i=n; i>=1; i--)
    {
        if(a[i]>ave) //向前面均匀一些 
        {
            d = a[i]-ave;
            a[i] -= d;
            a[i-1] += d;
            sum[i-1] += d;
            count++;
        }                    
    }
    cout << count;
     return 0;
}
以上代码来自洛谷用户gracelv 。
复制代码
posted @   storms11  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示