首页 > 其他分享 >题解 P1031 [NOIP2002 提高组] 均分纸牌

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

时间:2024-07-17 20:32:31浏览次数:26  
标签:纸牌 NOIP2002 int 题解 P1031 arg 这堆 ans sum

贪心

题中描述

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

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

易知均分完后,每堆牌的数量都为纸牌总数的平均数 \(\mathrm{arg}\) 。

所以我们可以预处理每堆牌跟 \(\mathrm{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;

显然可以分三种情况:

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

显然我们可以保证 \(1 \sim i - 1\) 已经是局部最优解。于是第 \(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
    }
}

由于 \(a_{i+1} - (-a_i)\) 等于 \(a_{i + 1} + a_i\) 。

于是 \(a_i > 0\) 和 \(a_i < 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;
}

标签:纸牌,NOIP2002,int,题解,P1031,arg,这堆,ans,sum
From: https://www.cnblogs.com/lstylus/p/18308218

相关文章

  • [题解]POJ3675 Telescope——求多边形与圆相交部分的面积
    POJ3675Telescope题意简述多测。每次给定一个\(N\)边形(保证相邻输入的顶点在多边形上也是邻接的),再给定一个以\((0,0)\)为圆心,半径为\(r\)的圆。请计算出多边形和圆相交部分的面积(保留\(2\)位小数)。\(3\leN\le50\)\(0.1\ler\le1000\)\(-1000\lex_i,y_i\le1000\)。......
  • ABC361-D题解
    背景保佑LC能来一中。题意给你一个长度为\(n\)的初始字符串和目标字符串,都由W和B两种字符构成。现在初始字符串末尾接有两个空格字符,每次你可以在该字符串中选出连续两个非空格字符,并把它们按顺序与两个空格交换位置。问最少需要几步能得到目标字符串。分析首先如果两......
  • ABC361-C题解
    背景昨天打比赛的时候查了中考分,心快停跳了。题意从\(n\)个数字中删除\(k\)个数字,问剩下的数字中极差的最小值。分析首先把这\(n\)个数字排序,然后问题就可以转化为求这\(n\)个数字中所有长度为\(n-k\)的连续子段的极差的最小值。采用尺取法,可以从\(1\)开始枚举......
  • 题解:AT_abc360_c [ABC360C] Move It
    背景机房大佬掉大分了,乐悲。题意给你几个箱子和每个箱子里装有的东西\(a\)和对应的重量\(w\),现在要让每个箱子里都装有一个东西,每次可以移动任意一个箱子中的任意一个东西,代价为它的重量,问最小代价。分析贪心。首先最终状态里所有箱子一定只有一个东西,那么对于所有装东西......
  • 题解:P10723 [GESP202406 七级] 黑白翻转
    背景汗流浃背了。分析容易想到一个显然的思路:以任意节点为根,开始遍历。如果一个节点的子树里面有黑点,那么它必须保留,否则如果它是白点,则可以删去。但这个方法很容易举出反例:在这颗树中,如果以最上面的白点为根,那么手推发现算法显然错误。尝试进行修改,容易发现,对于类似的情况......
  • 题解:P10722 [GESP202406 六级] 二叉树
    题意一颗\(n\)节点的二叉树,每个节点非黑即白,给你\(Q\)次操作,每次给你一个\(u\),把\(u\)的子树内所有节点颜色反转,问最终每个节点的颜色。分析看到数据范围,首先把操作离线。容易发现如果一个节点重复操作奇数次,等效于操作一次,如果重复操作偶数次,等效于没操作。所以我们可......
  • 题解:B3646 数列前缀和 3
    分析板子题,线段树维护矩阵区间积,除了难写没什么思维难度。所以直接放代码吧。Code#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;inlineintread(){ intx=0,f=1;charch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getcha......
  • Masked Popcount 题解
    背景罚了一发,太菜了。为什么我终于有时间的时候她要考试?题意给你\(n,m\),问\(\sum_{i=0}^{n}popcount(i\&m)\)。其中\(\&\)代表位运算,\(popcount\)代表一个数字二进制下\(1\)的个数。分析两个数字在二进制下根据数据范围有\(60\)位。所以我们考虑每一位对答案的贡......
  • 题解:AT_abc359_c [ABC359C] Tile Distance 2
    背景去中考了,比赛没打,来补一下题。分析这道题让我想起了这道题(连题目名称都是连着的),不过显然要简单一些。这道题显然要推一些式子。我们发现,和上面提到的那道题目一样,沿着对角线走台阶,纵坐标走到以后再走横坐标显然是最优策略。这时候的答案就是横纵坐标差的和的一半(这就不用......
  • 题解:AT_abc357_f [ABC357F] Two Sequence Queries
    题意维护一个数据结构,支持两个数列的区间求和,和查询区间内两数列各元素积的和。分析线段树万岁!这道题要维护两个序列,所以线段树中要同时存储两个区间和。但还要在维护一个信息,是该区间内两序列元素积的和。大概长这样:structno{ intl,r; intda,db,ab; intta,tb;}t[m......