【学军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;
}
posted @ 2021-11-17 21:47  あおいSakura  阅读(54)  评论(0)    收藏  举报