AGC043 B题题解

有的时候,碰到一道题,要给自己先设立部分分,再去想如何把部分分推广到一般情况。这题就是绝佳的例子。

不妨将\(a_i\)\(a_i - 1\)替代,这样就变成了\(a_i \in \{ 0, 1, 2\}\)了。

我们给自己设立的部分分是\(a_i \in \{ 0, 1 \}\)时怎么做。

我们会发现\(x_{i, j} \equiv x_{i - 1, j} + x_{i - 1, j + 1} (\bmod 2)\)了。于是我们在\(\bmod 2\)意义下计算出\(x_{n, 1}\)即可。

用简单的归纳法即可得到\(x_{n, 1} \equiv \sum_{i = 1}^{n} {{{n - 1} \choose {i - 1}} a_i} (\bmod 2)\)

我们接下来的工作是研究这个做法如何推广。我们发现这个做法能够计算出\(x_{n, 1} \mod 2\)的值。如果发现它模2余1,就可以唯一确定它是1。否则我们要辨别它到底是\(0\)还是\(2\)

如果\(x_{1, 1}, ... x_{n, 1}\)中有一个\(1\)的话,分析\(x_{i, 1}, ..., x_{i, n + 1 - i}\)这些数。如果它有一些\(1\)且不全是\(1\)的话,那么\(x_{i + 1, 1}, ..., x_{i + 1, n - i}\)这一行也必定有\(1\)。如果每一行都满足这一行的数必定有\(1\)的话,那么\(x_{n, 1} = 1\),与我们之前的假设矛盾。因此我们一定有一行全是\(1\),这样才能生成一个没有\(1\)的一行。在这一行之后所有数都变成\(0\)了,所以\(x_{n, 1} = 0\)

否则我们又可以假设\(x_{1, 1}, ..., x_{n, 1}\)全部不为\(1\),将它们通通除以\(2\)后再使用部分分的算法即可!、

时间复杂度为\(O(n)\),可以轻松通过此题。

代码如下:

#include <bits/stdc++.h>
#define debug(x) cerr << #x << " " << (x) << endl
using namespace std;

const int N = 1000005;

template <class T>
void read (T &x) {
	int sgn = 1;
	char ch;
	x = 0;
	for (ch = getchar(); (ch < '0' || ch > '9') && ch != '-'; ch = getchar()) ;
	if (ch == '-') ch = getchar(), sgn = -1;
	for (; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	x *= sgn;
}
template <class T>
void write (T x) {
	if (x < 0) putchar('-'), write(-x);
	else if (x < 10) putchar(x + '0');
	else write(x / 10), putchar(x % 10 + '0');
}

char str[N];
int n, a[N];

int main () {
	read(n), n--;
	scanf("%s", str);
	for (int i = 0; i <= n; i++) a[i] = str[i] - '1';

	int ans = 0;
	for (int i = 0; i <= n; i++) {
		if ((n & i) == i) ans = (ans + a[i]) % 2;
	}
	if (!ans) {
		bool flag = true;
		for (int i = 0; i <= n; i++) {
			if (a[i] == 1) flag = false;
		}
		if (flag) {
			int x = 0;
			for (int i = 0; i <= n; i++) a[i] >>= 1;
			for (int i = 0; i <= n; i++) {
				if ((n & i) == i) x = (x + a[i]) % 2;
			}
			if (x) ans = 2;
		}
	}
	write(ans), putchar('\n');
	return 0;
}
posted @ 2020-03-25 15:54  unzcjouhi  阅读(318)  评论(0编辑  收藏  举报