题解 P1031 [NOIP2002 提高组] 均分纸牌

贪心

题中描述

每一堆牌只能移动若干张牌到相邻的牌堆上

确定了局部最优解必定能推导出全局最优解。

易知均分完后,每堆牌的数量都为纸牌总数的平均数 arg

所以我们可以预处理每堆牌跟 arg 的差距

for (int i = 1; i <= n; ++i) sum += a[i];
int arg = sum / n;
for (int i = 1; i <= n; ++i) a[i] -= arg;

显然可以分三种情况:

  • ai=0 时,此时这堆牌不需要移动
  • ai<0 时,这堆牌需要从其他堆拿过来
  • ai>0​ 时,这堆牌需要全部给其他牌

显然我们可以保证 1i1 已经是局部最优解。于是第 i 堆只需要给第 i+1 堆或从第 i+1​ 堆拿过来。

写出代码

for (int i = 1; i <= n; ++i) {
    if (a[i] == 0) continue; // 不需要移动
    else if (a[i] > 0) { // 大于0
        a[i + 1] += a[i]; // 给后面的人
        ans ++; // 次数加1
    }else {
        a[i + 1] -= (-a[i]); // 从后面补到0
        ans ++; // 次数加1
    }
}

由于 ai+1(ai) 等于 ai+1+ai

于是 ai>0ai<0 时代码一样

可以简化代码为:

for (int i = 1; i <= n; ++i) {
    if (a[i] == 0) continue;
    a[i + 1] += a[i];
    ans ++;
}

Code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

int n;
int a[N];
int sum = 0, ans = 0;

int main() {
    ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);

    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i], sum += a[i];

    int arg = sum / n;
    for (int i = 1; i <= n; ++i) a[i] -= arg;
    for (int i = 1; i <= n; ++i) {
        if (!a[i]) continue;
        a[i + 1] += a[i];
        ans ++;
    }
    cout << ans;
    return 0;
}
posted @   lyfandlzf  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示