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 2≤N≤500
- 1 ≤ A i ≤ 1 0 6 1\\leq A_i\\leq 10^6 1≤Ai≤106
- 0 ≤ K ≤ 1 0 9 0\\leq K \\leq 10^9 0≤K≤109
输出描述
输出一行一个整数
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=0∗10),变化数量位 1 1 1
2 2 2要变成 10 10 10的倍数,最快的方法就是变成 0 0 0( 0 = 0 ∗ 10 0=0*10 0=0∗10),变化数量位 2 2 2
7 7 7要变成 10 10 10的倍数,最快的方法就是变成 10 10 10( 10 = 1 ∗ 10 10=1*10 10=1∗10),变化数量位 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 1∼sum,如果 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集训队每周程序设计竞赛题解