均分
题目链接:学军NOIP开放题2-D
题目大意
要你给 n 个数赋值,然后使得每个数满足它标识数对应的条件。
标识数是 0 则剩下的 n-1 个数不能分成和相同的两堆,是 1 就是可以。
然后判断无解,或者给出构造方案。
思路
我们考虑根据这个大致思路来构造,就是尽可能的让不可以分成的和是奇数。
然后开始分类讨论:(下面让 c 0 , c 1 c0,c1 c0,c1 为标识符为 0 , 1 0,1 0,1 的个数)
首先判掉两个特殊的,就是只有 0 0 0 或 1 1 1。
只有 0 0 0 就如果 c 1 c1 c1 是偶数就全都是 1 1 1,如果是奇数你可以 c 1 − 2 c1-2 c1−2 个 1 1 1,然后一个 10000 10000 10000 一个 9999 9999 9999。
只有 1 1 1 就如果 c 0 c0 c0 是奇数就全是 1 1 1,否则就无解。
无解这里可以证一下,首先如果所有数的 gcd > 1 \gcd>1 gcd>1 我们可以同除效果不变。
那因为你要全部有解,那一定至少总和一定要都是偶数,所以所有数奇偶性相同。
如果都是偶数就可以同除 2 2 2,那如果是奇数那总和就一定是奇数(奇数*奇数=奇数),所以就无解了。
然后再判掉两个: c 0 = 1 , c 1 = 1 c0=1,c1=1 c0=1,c1=1
c 0 = 1 c0=1 c0=1 的话如果 c 1 = 2 c1=2 c1=2 就无解,否则我们可以这样构造:
0 0 0 的那个放 n − 2 n-2 n−2,然后 1 1 1 中放一个 2 n − 5 2n-5 2n−5,其它都放 1 1 1。
c 1 = 1 c1=1 c1=1 的时候 1 1 1 的位置放 1 1 1, 0 0 0 的放 c 0 − 1 c0-1 c0−1 个 2 2 2,一个 2 ∗ c 0 − 2 2*c0-2 2∗c0−2。
然后再按 c 0 , c 1 c0,c1 c0,c1 的奇偶分类讨论。
如果 c 1 c1 c1 是奇数,那就好办了,直接 1 1 1 的填 1 1 1, 0 0 0 的填 2 2 2。
如果 c 1 c1 c1 是偶数,我们就看 c 0 c0 c0。
如果 c 0 c0 c0 是偶数,那也好办 1 1 1 的填 2 2 2, 0 0 0 的填 1 1 1。
如果 c 1 c1 c1 是奇数,我们可以这样: 0 0 0 里面一个 100 100 100,一个 2 2 2,剩下的都是 1 1 1,然后 1 1 1 里面都是所有 0 0 0 填的数的和。
这些自己证明一下都可以证出来。
然后就可以了。
代码
#include<cstdio>
#include<cstring>
using namespace std;
int T, c0, c1, n, ans[51];
int pl0[51], pl1[51];
char s[101];
int main() {
// freopen("div.in", "r", stdin);
// freopen("div.out", "w", stdout);
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
scanf("%s", s + 1);
c0 = c1 = 0;
for (int i = 1; i <= n; i++)
if (s[i] == '0') c0++, pl0[c0] = i;
else c1++, pl1[c1] = i;
if (c0 == 0) {
if (c1 & 1) {
printf("Yes\n");
for (int i = 1; i <= n; i++)
printf("1 ");
printf("\n");
}
else printf("No\n");
continue;
}
if (c1 == 0) {
if (c0 & 1) {
printf("Yes\n");
printf("10000 9999 ");
for (int i = 3; i <= n; i++) printf("1 ");
printf("\n");
}
else {
printf("Yes\n");
for (int i = 1; i <= n; i++) printf("1 ");
printf("\n");
}
continue;
}
if (c0 == 1 && (n & 1)) {
if (c1 == 2) printf("No\n");
else {
printf("Yes\n");
ans[pl0[1]] = n - 2;
ans[pl1[1]] = n - 2 + n - 3;
for (int i = 2; i <= c1; i++) ans[pl1[i]] = 1;
for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
printf("\n");
}
continue;
}
if (c1 == 1) {
printf("Yes\n");
ans[pl1[1]] = 1;
for (int i = 1; i < c0; i++) ans[pl0[i]] = 2;
ans[pl0[c0]] = 2 * c0 - 2;
for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
printf("\n");
continue;
}
if (c1 & 1) {
printf("Yes\n");
for (int i = 1; i <= c1; i++) ans[pl1[i]] = 1;
for (int i = 1; i <= c0; i++) ans[pl0[i]] = 2;
for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
printf("\n");
}
else {
printf("Yes\n");
if (c0 & 1) {
int sum = 0;
ans[pl0[1]] = 100; ans[pl0[2]] = 2; sum = 102;
for (int i = 3; i <= c0; i++) ans[pl0[i]] = 1, sum++;
for (int i = 1; i <= c1; i++) ans[pl1[i]] = sum;
}
else {
for (int i = 1; i <= c0; i++) ans[pl0[i]] = 1;
for (int i = 1; i <= c1; i++) ans[pl1[i]] = 2;
}
for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
printf("\n");
}
}
return 0;
}