AtCoder Regular Contest 191 (Div. 2)

ARC191A Replace Digits

除了最后一个字符必须在 \(s\) 中,其他字符都是随意的。

从高往低一次填即可,能填最后一个就填,否则就填前面的。

最后再把最后一个字符放到最后一个位置即可。

constexpr int N = 1e6 + 5;
int n, m, cnt[10], ans[N];
char s[N], t[N];

void slv() {
	Read(n, m), Read(s), Read(t);
	for (int i = 0; i + 1 < m; i ++)
		++ cnt[t[i] - '0'];
	int mx = 9; bool chs = false;
	int lst = t[m - 1] - '0';
	for (int i = 0; i < n; i ++) {
		ans[i] = s[i] - '0';
		while (mx >= 0 && !cnt[mx]) mx --;
		if (mx > ans[i]) {
			if (!chs && lst >= mx) {
				ans[i] = lst, chs = true;
				continue;
			}
			ans[i] = mx, cnt[mx] --;
		} else if (!chs && lst > ans[i]) {
			ans[i] = lst, chs = true;
		}
	}
	if (!chs) {
		for (int i = 0; i < n; i ++)
			if (ans[i] <= lst) {
				ans[i] = lst, chs = true;
				break;
			}
		if (!chs) {
			ans[n - 1] = lst;
		}
	}
	for (int i = 0; i < n; i ++) Write(ans[i]);
	return;
}

ARC191B XOR = MOD

首先 \(n \le x < 2n\),那么就是说我们只需要考虑 \(x - n = x \oplus n\) 的情况。

不难发现这其实就是在说二进制下 \(x\)\(n\) 的超集。

void slv() {
	int n, k; Read(n, k);
	int len = __lg(n);
	vector<int> bit;
	for (int i = 0; i <= len; i ++)
		if (!(n >> i & 1)) bit.emplace_back(i);
	-- k;
	if (1 << bit.size() <= k) {
		Puts("-1");
		return;
	}
	int ans = n;
	for (int i = 0; i < bit.size(); i ++)
		if (k >> i & 1) ans |= 1 << bit[i];
	Write(ans, '\n');
	return;
}

C - A^n - 1

构造 \((A, M) = (N + 1, N^2)\),正确性显然。

诗人?

D - Moving Pieces on Graph

就摁分讨,没营养。

懒得写了。

E - Unfair Game

发现每个袋子是几乎独立的,考虑一个袋子的情况。

发现能不能赢是只和奇偶性相关的,所以可以把 \((X, Y, A, B)\) 替换成 \((X \bmod 2, Y \bmod 2, A, B \bmod 2)\)

进行分类讨论:

  • \(X = Y\),可以直接看 \(A \cdot (X + 1) + B\) 的奇偶性。
  • \(X = 0, Y = 1\),那么在 \(A \neq 0\) 时先手是有机会调节奇偶性的,之后只需要逼迫后手选金币就赢了。
  • \(X = 1, Y = 0\),如果 \(A > 1\) 和上面的是相同的,\(A \le 1\) 可以搜。

综上,在 \(X = Y\) 时,先手必胜当且仅当 \(A\cdot (X + 1) +B\) 是奇数;否则可以将 \((X, Y, A, B)\) 替换成 \((X \bmod 2, Y \bmod 2, \min(A, 2), B \bmod 2)\) 后爆搜。

对于多个袋子的情况,可以把每个袋子 \((A, B)\) 我们可以把它看成一个二元组 \((a, b)\),表示对于两个人来说是不是先手必胜的。

对于一个先手必胜的袋子,它的影响其实就是交换先后手。

所以假设 Takahashi 有 \(x\) 个先手必胜的袋子,Aoki 有 \(y\) 个先手必胜的袋子,那么 Takahashi 赢的充要条件就是 \(x >y\)

如果记 \((a, b)\) 类型的袋子个数为 \(c_{a, b}\),那么方案数为:

\[\begin{aligned} ans &= \sum_{k > 0} [z^k] (z^0 + z^0)^{c_{0, 0}} (z^0 + z^{-1})^{c_{0, 1}} (z^1 + z^0)^{c_{1, 0}} (z^1 + z^{-1})^{c_{1, 1}} \\ &= \sum_{k > 0} [z^k] 2^{c_{0, 0}} z^{- c_{0, 1} - c_{1, 1}} (z^1 + 1)^{c_{0,. 1} + c_{1, 0}}(z^2 + 1)^{c_{1, 1}} \\ &= 2^{c_{0, 0}} \sum_{k > c_{0, 1} + c_{1, 1}} [z^k] (1+z)^{c_{0, 1} + c_{1, 0}} (1+z^2)^{c_{1, 1}} \end{aligned} \]

那么就是要求 \(F(z) = \displaystyle (1+z)^A (1+z^2)^B\) 的各项系数。

其 ODE 是:

\[(1+z+z^2+z^3) F' = \big( (A + 2B) z^2 + 2Bz +A \big) F \]

可以得到递推式:

\[(n+1) f_{n + 1} = (A - n) f_n + (2B - n + 1) f_{n - 1} + (A + 2B - n+ 2) f_{n - 2} \]

时间复杂度线性。

bool win[2][2][3][2], vis[2][2][3][2];

void slv() {
	int n, X, Y;
	Read(n, X, Y);
	X &= 1, Y &= 1;
	
	auto chk = [&](auto self, int X, int Y, int A, int B) -> bool {
		if (vis[X][Y][A][B]) {
			return win[X][Y][A][B];
		}
		vis[X][Y][A][B] = true;
		if (A != 0) {
			if (!self(self, Y, X, A - 1, (B + X) & 1)) {
				return win[X][Y][A][B] = true;
			}
		}
		if (B != 0) {
			if (!self(self, Y, X, A, B - 1)) {
				return win[X][Y][A][B] = true;
			}
		}
		return win[X][Y][A][B] = false;
	};
	
	array<array<int, 2>, 2> c;
	c[0][0] = c[0][1] = c[1][0] = c[1][1] = 0;
	for (int i = 0; i < n; i ++) {
		int A, B; Read(A, B);
		if (X == Y) {
			int o = ((X + 1) * A + B) & 1;
			++ c[o][o];
		} else {
			int o0 = chk(chk, X, Y, min(2, A), B & 1),
					o1 = chk(chk, Y, X, min(2, A), B & 1);
			++ c[o0][o1];
		}
	}
	
	vector<mint> f(2 * n + 1);
	int A = c[1][0] + c[0][1], B = c[1][1];
	
	f[0] = 1, f[1] = A, f[2] = comb.C(A, 2) + B;
	for (int i = 2; i < 2 * n; i ++) {
		f[i + 1] += (A - i) * f[i];
		f[i + 1] += (2 * B - i + 1) * f[i - 1];
		f[i + 1] += (A + 2 * B - i + 2) * f[i - 2];
		f[i + 1] *= comb.inv(i + 1);
	}
	
	mint ans = 0;
	for (int i = c[0][1] + c[1][1] + 1; i <= 2 * n; i ++) {
		ans += f[i];
	}
	while (c[0][0] --) {
		ans *= 2;
	}
	Write((int)ans, '\n');
	
	return;
}
posted @ 2025-03-13 15:23  definieren  阅读(37)  评论(0)    收藏  举报