2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 E: 欢聚一堂- 题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 E: 欢聚一堂- 题解相关的知识,希望对你有一定的参考价值。


欢聚一堂

时间限制:2秒
空间限制:1024M


题目描述

N N N个小朋友欢聚一堂,第 i i i个小朋友有 A i A_i Ai个糖果

一次糖果赠送事件的定义是:小朋友 i i i赠送给小朋友 j j j一颗糖( A i A_i Ai减1, A j A_j Aj加1)

特殊的是,小朋友的糖果数量可以为负。(如果小朋友 i i i已经没有糖果了,但他对小朋友 j j j进行一次糖果赠送事件,那么事件完成之后,小朋友 i i i具有 − 1 -1 1颗糖果)

最多进行 K K K糖果赠送事件的前提下,请你找到最大的一个整数 a a a,使得 a a a是所有小朋友糖果的整数倍。


输入描述

输入包括 2 2 2
第一行空格隔开的两个正整数 N N N K K K,代表共有 N N N个小朋友,最多进行 K K K次糖果赠送事件
第二行空格隔开的 N N N个正整数 A i A_i Ai,代表 N N N个小朋友的初始糖果数量。

数据范围

  • 2 ≤ N ≤ 500 2\\leq N\\leq 500 2N500
  • 1 ≤ A i ≤ 1 0 6 1\\leq A_i\\leq 10^6 1Ai106
  • 0 ≤ K ≤ 1 0 9 0\\leq K \\leq 10^9 0K109

输出描述

输出一行一个整数 a a a,使得 a a a是进行不多于 K K K次的交换事件后,每个小朋友的糖果数量都是 a a a的整数倍。
在所有符合条件的 a a a中,输出最大的那一个。

例如有 2 2 2个小朋友,最多进行 10 10 10次糖果交换事件,初始时两个小朋友具有的糖果数量分别是 3 3 3 5 5 5
那么可以进行 3 3 3次糖果交换( 3 < 10 3<10 3<10),之后小朋友分别具有 0 0 0 8 8 8颗糖果。
此时有 a = 8 a=8 a=8,满足 0 = 0 × 8 0=0\\times8 0=0×8 8 = 1 × 8 8=1\\times8 8=1×8,因此 8 8 8是符合条件的 a a a
找不到一种不多于 10 10 10次的交换方法,使得交换之后有符号条件的更大的 a a a


样例一

输入

2 10
3 5

输出

8

题目分析

不论小朋友之间如何交换糖果,最终糖果的总数量必定不变。
如果每个数都能整除 a a a a a a是其中每个数的因数)
那么 a a a一定是和的因数。

因此,我们只需要枚举所有数的和的每一个因子就好了

记所有数的和为 s u m sum sum,对于 s u m sum sum的其中一个因子 i i i
我们只需要验证能否在 k k k步之内使得每个数都变成 i i i的倍数。

如果要把 1   2   7 1\\ 2\\ 7 1 2 7变成 10 10 10的倍数
首先我们用每一个数模上 10 10 10:$1%10=1,2 10 = 2 , 7 10=2,7%10=7 10=2,7
之后将取模后的结果存入数组 t e m p temp temp中从小到大并排序,
得到 t e m p temp temp数组: 1 , 2 , 7 1,2,7 1,2,7

1 1 1要变成 10 10 10的倍数,最快的方法就是变成 0 0 0 0 = 0 ∗ 10 0=0*10 0=010),变化数量位 1 1 1
2 2 2要变成 10 10 10的倍数,最快的方法就是变成 0 0 0 0 = 0 ∗ 10 0=0*10 0=010),变化数量位 2 2 2
7 7 7要变成 10 10 10的倍数,最快的方法就是变成 10 10 10 10 = 1 ∗ 10 10=1*10 10=110),变化数量位 3 3 3

也就是说,对于每一个temp中的元素,前面的较小的数字努力往下减,变成 0 0 0
同时temp中后面比较大的元素努力网上加,变成 10 10 10(正好前面减掉的数可以加给它)
看看至少需要几次才(是否小于等于 k k k)能全部变成 10 10 10的倍数。

我们只需要枚举 s u m sum sum的所有因数 i i i,判断是否能够在 k k k步之内全部变成 i i i的倍数。

对于 s u m sum sum的因数,我们可以枚举 i i i 1 ∼ s u m 1\\sim\\sqrtsum 1sum ,如果 s u m sum%i sum的值为 0 0 0,那么我们就找到了 s u m sum sum的两个因数 i i i s u m / i sum/i sum/i

对于给定的一个 i i i,我们排序后遍历一遍即可,复杂度 O ( n log ⁡ n ) O(n\\log n) O(nlogn)

总复杂度为 O ( s u m × n log ⁡ n ) O(\\sqrtsum\\times n\\log n) O(sum ×nlogn)
其中 M A X ( s u m ) = M A X ( a [ i ] ) × M A X ( n ) = 1 0 6 × 500 MAX(sum)=MAX(a[i])\\times MAX(n)=10^6\\times 500 MAX(sum)=MAX(a[i])×MAX(n)=106×500
能够在几十毫秒内求出。


AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int a[510];
int temp[510];
int n, k;
bool ok(int t)  // 判断是否可以在k步内把所有的数变成t的倍数
    for (int i = 0; i < n; i++) 
        temp[i] = a[i] % t;
    
    sort(temp, temp + n); // 排序
    int l = 0, r = n - 1以上是关于2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 E: 欢聚一堂- 题解的主要内容,如果未能解决你的问题,请参考以下文章

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛(10)题解

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解

2021-2022-1 ACM集训队每周程序设计竞赛题解

2021-2022-1 ACM集训队每周程序设计竞赛题解