ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Max GCD(贪心、枚举)

2022-06-14 11:01:19  阅读:123  来源: 互联网

标签:GCD int Max leq 枚举 ans include check


题意

给定一个长度为\(N\)的整数序列:\(A_1, A_2, \dots, A_N\)

你可以执行如下操作\(0 \sim K\)次:

  • 选择两个整数\(i\)和\(j\)满足\(i \neq j\),将\(A_i\)加\(1\),\(A_j\)减\(1\)(可能会出现负数)。

问最大的正整数\(x\),满足在\(K\)次操作内,把所有\(A_i\)变成\(x\)的倍数(\(0\)为任意正整数的倍数)

题目链接:https://atcoder.jp/contests/abc136/tasks/abc136_e

数据范围

\(2 \leq N \leq 500\)
\(1 \leq A_i \leq 10^6\)
\(0 \leq K \leq 10^9\)

思路

看到这道题,我的第一反应是二分答案。但是仔细分析一下,发现不满足二分性质。一个较小的数可能不满足要求,但是另一个较大的数有可能是满足要求的,因此不能二分。

但是枚举可能的答案,然后check应该是一个正确的思路,因此需要找一个候选答案集合。

我们考虑到,经过若干操作之后,序列的和(\(s = \sum\limits_{i=1}^N A_i\))是不变的。并且,所有\(A_i\)都为\(x\)的倍数,那么\(s\)也应该为\(x\)的倍数。因此,所有\(s\)的因数为候选答案集合,集合元素个数为\(O(\sqrt{N \max A_i})\)。

下面考虑如何check答案,这是一个经典贪心问题。假设当前枚举到的答案为\(x\),将\(A_i\)对\(x\)取模,然后从小到大排序。我们希望接近于\(0\)的数都减到\(0\),接近于\(x\)的数都加到\(x\)。因此,我们枚举分界点,分界点左边的元素全都减到\(0\),分界点右边的元素全都加到\(x\)。判断一下减的次数与加的次数是否相等,以及是否\(\leq K\)即可。这可以通过前缀和快速实现。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 510;

int n, k;
int a[N], b[N];
ll sum[N];

bool check(int x)
{
    for(int i = 1; i <= n; i ++) b[i] = a[i] % x;
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + b[i];
    for(int i = 1; i <= n; i ++) {
        ll t = (ll)x * (ll)(n - i);
        if(sum[i] == t - (sum[n] - sum[i]) && sum[i] <= k) {
            return true;
        }
    }
    return false;
}

int main()
{
    scanf("%d%d", &n, &k);
    ll tot = 0;
    for(int i = 1; i <= n; i ++) {
        scanf("%d", &a[i]);
        tot += a[i];
    }
    int ans = 1;
    for(int i = sqrt(tot); i >= 1; i --) {
        if(check(i)) ans = max(ans, i);
        if(check(tot / i)) ans = max((ll)ans, tot / i);
    }
    printf("%d\n", ans);
    return 0;
}

标签:GCD,int,Max,leq,枚举,ans,include,check
来源: https://www.cnblogs.com/miraclepbc/p/16373797.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有