【学军NOIP开放题2-D】均分(构造)(分类讨论)
均分
题目链接:学军NOIP开放题2-D
题目大意
要你给 n 个数赋值,然后使得每个数满足它标识数对应的条件。
标识数是 0 则剩下的 n-1 个数不能分成和相同的两堆,是 1 就是可以。
然后判断无解,或者给出构造方案。
思路
我们考虑根据这个大致思路来构造,就是尽可能的让不可以分成的和是奇数。
然后开始分类讨论:(下面让 \(c0,c1\) 为标识符为 \(0,1\) 的个数)
首先判掉两个特殊的,就是只有 \(0\) 或 \(1\)。
只有 \(0\) 就如果 \(c1\) 是偶数就全都是 \(1\),如果是奇数你可以 \(c1-2\) 个 \(1\),然后一个 \(10000\) 一个 \(9999\)。
只有 \(1\) 就如果 \(c0\) 是奇数就全是 \(1\),否则就无解。
无解这里可以证一下,首先如果所有数的 \(\gcd>1\) 我们可以同除效果不变。
那因为你要全部有解,那一定至少总和一定要都是偶数,所以所有数奇偶性相同。
如果都是偶数就可以同除 \(2\),那如果是奇数那总和就一定是奇数(奇数*奇数=奇数),所以就无解了。
然后再判掉两个:\(c0=1,c1=1\)
\(c0=1\) 的话如果 \(c1=2\) 就无解,否则我们可以这样构造:
\(0\) 的那个放 \(n-2\),然后 \(1\) 中放一个 \(2n-5\),其它都放 \(1\)。
\(c1=1\) 的时候 \(1\) 的位置放 \(1\),\(0\) 的放 \(c0-1\) 个 \(2\),一个 \(2*c0-2\)。
然后再按 \(c0,c1\) 的奇偶分类讨论。
如果 \(c1\) 是奇数,那就好办了,直接 \(1\) 的填 \(1\),\(0\) 的填 \(2\)。
如果 \(c1\) 是偶数,我们就看 \(c0\)。
如果 \(c0\) 是偶数,那也好办 \(1\) 的填 \(2\),\(0\) 的填 \(1\)。
如果 \(c1\) 是奇数,我们可以这样:\(0\) 里面一个 \(100\),一个 \(2\),剩下的都是 \(1\),然后 \(1\) 里面都是所有 \(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;
}

浙公网安备 33010602011771号