题目 | Candy Party
Codeforces Round 896 (Div. 2)
D1. Candy Party (Easy Version)
D2. Candy Party (Hard Version)
https://codeforces.com/contest/1869/problem/D1
https://codeforces.com/contest/1869/problem/D2
2 seconds / 256 megabytes
standard input / standard output
Problem (Easy Version)
This is the easy version of the problem. The only difference is that in this version everyone must give candies to exactly one person and receive candies from exactly one person. Note that a submission cannot pass both versions of the problem at the same time. You can make hacks only if both versions of the problem are solved.
After Zhongkao examination, Daniel and his friends are going to have a party. Everyone will come with some candies.
There will be
- Choose an integer
( ) and a non-negative integer , then give his candies to the -th person. Note that one cannot give more candies than currently he has (he might receive candies from someone else before) and he cannot give candies to himself.
Daniel likes fairness, so he will be happy if and only if everyone receives candies from exactly one person. Meanwhile, his friend Tom likes average, so he will be happy if and only if all the people have the same number of candies after all swaps.
Determine whether there exists a way to swap candies, so that both Daniel and Tom will be happy after the swaps.
Input
The first line of input contains a single integer
The first line of each test case contains a single integer
The second line of each test case contains
It is guaranteed that the sum of
Output
For each test case, print "Yes" (without quotes) if exists a way to swap candies to make both Daniel and Tom happy, and print "No" (without quotes) otherwise.
You can output the answer in any case (upper or lower). For example, the strings "yEs", "yes", "Yes", and "YES" will be recognized as positive responses.
Example
Input
6
3
2 4 3
5
1 2 3 4 5
6
1 4 7 1 5 4
2
20092043 20092043
12
9 9 8 2 4 4 3 5 1 1 1 1
6
2 12 7 16 11 12
Output
Yes
Yes
No
Yes
No
No
Note
In the first test case:
- The first person gives
candy to the third person; - The second person gives
candies to the first person; - The third person gives
candy to the second person.
Then all people have
In the second test case:
- The fifth person gives
candies to the first person, from now on the first person has candies; - The first person gives
candies to the third person; - The third person gives
candies to the fifth person; - The fourth person gives
candies to the second person; - The second person gives
candy to the fourth person.
Then all people have
In the third test case, it's impossible for all people to have the same number of candies.
In the fourth test case, the first person gives
题解 (Easy Version)
首先特判总数是否能够平均,即先求出糖果总数,再判断是否能被人数整除,如果不能被整除则输出 No
结束。
在简单版题目中,限制为每个人必须严格收到一次糖果,即等价于每个人必须严格赠送一次糖果,并且收到和赠送的糖果必须为
记第
那么我们第二次判断的依据便是上面的公式,即判断糖果变化量
判断方式很简单,即观察
如果
将所有初始糖果数判断一遍,只要出现一个不可拆分的,则说明不合法,输出 No
结束。
那么对于
接下来,还有需要满足的条件,即收到和赠送的糖果数必须一一对应,因为如果有一个人赠送了
我们可以使用一个数组记录幂次为 No
结束。
代码 (Easy Version)
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
pair<int, int> bin_split(int x)
{
int start = -1;
int t = x, digit = 0;
while (t)
{
digit++;
t /= 2;
}
for (int i = 0; i < digit; i++)
{
if (start == -1 && (x >> i & 1) == 1)
start = i;
else if (start != -1 && (x >> i & 1) == 0)
return {-1, -1};
}
return {start, digit};
}
void solve()
{
int n;
cin >> n;
vector<int> a(n + 10);
for (int i = 1; i <= n; i++)
cin >> a[i];
int sum = accumulate(a.begin() + 1, a.begin() + 1 + n, 0LL);
if (sum % n)
{
cout << "No" << endl;
return;
}
int mean = sum / n;
vector<int> remain(40);
int same = 0;
for (int i = 1; i <= n; i++)
if (a[i] == mean)
same++;
for (int i = 1; i <= n; i++)
{
if (a[i] == mean)
continue;
int delta = abs(a[i] - mean);
auto splt = bin_split(delta);
if (splt.first == -1)
{
cout << "No" << endl;
return;
}
if (a[i] > mean)
{
remain[splt.first]--;
remain[splt.second]++;
}
else
{
remain[splt.first]++;
remain[splt.second]--;
}
}
for (int i = 0; i < remain.size(); i++)
{
if (remain[i])
{
cout << "No" << endl;
return;
}
}
cout << "Yes" << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
Problem (Hard Version)
困难版题面省略,可以自行去原页面查看。困难版与简单版的区别:
This is the hard version of the problem. The only difference is that in this version everyone must give candies to no more than one person and receive candies from no more than one person. Note that a submission cannot pass both versions of the problem at the same time. You can make hacks only if both versions of the problem are solved.
题解 (Hard Version)
困难版与简单版的唯一区别就是,一个人可以不收到糖果,也可以不发送糖果。那么首先需要分析这个区别到底影响了什么。
容易发现,之前我们拆分两个
- 如果
不是 的幂次:只可按照上文方式拆分为两个 的幂次相减 - 如果
是 的幂次:可按照上文方式拆分为两个 的幂次相减,也可以不拆分,直接发送或收到其本身。
可以发现,如果
为了解决这个问题,对于
具体的流程是,使用三个数组
对于
对于
如果
如果
如果过程当中发现不够拆,那么就不合法输出 No
. 如果发现第 No
.
代码 (Hard Version)
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
pair<int, int> bin_split(int x)
{
int start = -1;
int t = x, digit = 0;
while (t)
{
digit++;
t /= 2;
}
for (int i = 0; i < digit; i++)
{
if (start == -1 && (x >> i & 1) == 1)
{
start = i;
}
else if (start != -1 && (x >> i & 1) == 0)
{
return {-1, -1};
}
}
return {start, digit};
}
int log_2(int x)
{
int num = 1, pow = 0;
while (num < x)
{
num *= 2;
pow++;
}
return num == x ? pow : -1;
}
void solve()
{
int n;
cin >> n;
vector<int> a(n + 10);
for (int i = 1; i <= n; i++)
cin >> a[i];
int sum = accumulate(a.begin() + 1, a.begin() + 1 + n, 0LL);
if (sum % n)
{
cout << "No" << endl;
return;
}
int mean = sum / n;
vector<int> remain(40), add(40), sub(40);
for (int i = 1; i <= n; i++)
{
if (a[i] == mean)
continue;
int delta = abs(a[i] - mean);
int pow = log_2(delta);
if (pow != -1)
{
if (a[i] > mean)
sub[pow]++;
else
add[pow]++;
continue;
}
auto splt = bin_split(delta);
if (splt.first == -1)
{
cout << "No" << endl;
return;
}
if (a[i] > mean)
{
remain[splt.first]--;
remain[splt.second]++;
}
else
{
remain[splt.first]++;
remain[splt.second]--;
}
}
for (int i = 31; i >= 0; i--)
{
remain[i] += sub[i];
remain[i] -= add[i];
if (i == 0)
break;
if (remain[i] < 0)
{
sub[i - 1] += remain[i];
remain[i - 1] += remain[i];
if (sub[i - 1] < 0)
{
cout << "No" << endl;
return;
}
}
else
{
add[i - 1] -= remain[i];
remain[i - 1] += remain[i];
if (add[i - 1] < 0)
{
cout << "No" << endl;
return;
}
}
}
if (remain[0] == 0)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi