CF1076G Array Game

CF1076G Array Game

手推出大半,不会实现。

记必胜点表示走到此点时,下一手必胜;必败点同理。

每人都想要对方走到必胜点自己走到必败点。

有一种想法。

preipre_i 表示 [1,i][1,i] 后缀第一个奇数的位置。

容易发现,对于询问 [l,r][l,r]prerpre_r 为必败点,[prer+1,r][pre_r+1,r] 为必胜点。

由于最多可前进 mm 格,那么 [prer1,prerm][pre_r-1,pre_r-m] 为必胜点。

那么转化为谁先让 aprerm1a_{pre_r-m-1}00 谁赢,即如果 prerm1pre_r-m-1 为偶格,为必胜点,否则为必败点。

就是操作 [l,prerm1][l, pre_r-m-1] 谁必胜。

但是这样极其难修改,考虑根据上述启发必胜态到必败态或者反过来的转移。

偶格必为必胜点,因为如果后面 mm 格有必败点可直接过去,否则全为必胜点就在原地不动,让对手到将棋移到必胜点。

奇格必胜,当且仅当可移到必败,显然此时不动不是最优的选择,因为奇偶性变了。

只需要知道每个点可移到的第一个必败点的位置,只有 m+1m+1 种不同取值。

然后考虑分块,记录在块的右端点的首个必败点距离确定时,走到块的左端点的首个必败点的距离。

预处理,对于每个值,处理 m+1m+1 种不同取值即可。

考虑修改,加偶数不改变奇偶性,加奇数则为区间翻转。

顺便记录一下区间翻转后的答案覆盖即可。

时间复杂度大致是 O(nn)\mathcal O(n\sqrt n),带个 mm 的小常数。

#include <cstdio>

typedef long long ll;

#define ha putchar(' ')
#define he putchar('\n')

inline int read() {
	int x = 0;
	char c = getchar();
	while (c < '0' || c > '9')
		c = getchar();
	while (c >= '0' && c <= '9')
		x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}

#define js(l, r, fail, tg, fl) for (int j = r; j >= l; --j) if ((fl ^ (!(a[j] ^ tg))) || fail <= m) fail++; else fail = 1;

inline int min(int x, int y)
{
	return x < y ? x : y;
}

const int _ = 2e5 + 10, BL = 50, S = _ / BL + 10;;

int n, m, q, a[_], bel[_], L[S], R[S], f[2][S][7];

bool rev[S];

void build(int id) {
	for (int i = 1; i <= m + 1; ++i) {
		f[0][id][i] = f[1][id][i] = i;
		js(L[id], R[id], f[0][id][i], 0, 0);
		js(L[id], R[id], f[1][id][i], 0, 1);
		f[0][id][i] = min(f[0][id][i], m + 1), f[1][id][i] = min(f[1][id][i], m + 1);
	}
}

signed main() {
	n = read(), m = read(), q = read();
	for (int i = 1; i <= n; ++i) a[i] = read() & 1ll, bel[i] = (i - 1) / BL + 1;
	for (int i = 1; i <= bel[n]; ++i) L[i] = R[i - 1] + 1, R[i] = i * BL;
	R[bel[n]] = n;
	for (int i = 1; i <= bel[n]; ++i) build(i);
	int opt, l, r, c;
	while (q--) {
		opt = read(), l = read(), r = read();
		if (opt == 1) {
			c = read() & 1ll;
			if (!c) continue;
			if (bel[l] == bel[r]) {
				for (int i = l; i <= r; ++i) a[i] ^= 1;
				build(bel[l]);
				continue;
			}
			for (int i = l; i <= R[bel[l]]; ++i) a[i] ^= 1;
			build(bel[l]);
			for (int i = bel[l] + 1; i <= bel[r] - 1; ++i) rev[i] ^= 1;
			for (int i = L[bel[r]]; i <= r; ++i) a[i] ^= 1;
			build(bel[r]);
		} else {
			int fail = m + 1;
			if (bel[l] == bel[r]) {
				js(l, r, fail, rev[bel[l]], 0);
				putchar(fail == 1 ? '2' : '1'), he;
				continue;
			}
			js(L[bel[r]], r, fail, rev[bel[r]], 0);
			fail = min(fail, m + 1);
			for (int i = bel[r] - 1; i >= bel[l] + 1; --i)
				fail = f[rev[i]][i][fail];
			js(l, R[bel[l]], fail, rev[bel[l]], 0);
			fail = min(fail, m + 1);
			putchar(fail == 1 ? '2' : '1'), he;
		}
	}
	return 0;
}
posted @ 2022-08-11 21:24  蒟蒻orz  阅读(2)  评论(0编辑  收藏  举报  来源