uoj342

题意

\(n\) 种 Toads and Frogs 局面,每种局面有 \(a_i\) 个,每种局面的每个游戏可以选或者不选。

\(2^{\sum_{i\ =\ 1}^n\ a_i}\) 个状态中 \(L\) 必胜,\(R\) 必胜,先手必胜,后手必胜分别由多少个。对 \(998244353\) 取模。

\(1\ \leq\ \sum_{i\ =\ 1}^n\ a_i\ \leq\ 10^6\)

做法1

考虑如何确定一种状态的胜负情况。用 \(surreal\ number\),令 \(*\ =\ \{0|0\},\ \uparrow\ =\ \{0|*\},\ \downarrow\ =\ \{*|0\}\)
\(*\ +\ *\ =\ 0,\ \{\uparrow|\downarrow\}\ =\ *,\ \uparrow\ +\ \downarrow\ =\ 0\)
所以可以把多的 \(*\) 去掉,\(\downarrow\) 可以看成 \(-\uparrow\)
当数字和 \(>\ 0\) 时,\(L\) 必胜。
当数字和 \(<\ 0\) 时,\(R\) 必胜。
当数字和为 \(0\) 的时候,如果没有 \(*\) 时,\(cnt_\uparrow\ -\ cnt_\downarrow\ =\ 0\) 时后手必胜,否则如果 \(\uparrow\) 多则 \(L\) 必胜,\(\downarrow\) 多则 \(R\) 必胜。
当数字和为 \(0\) 的时候,如果没有 \(*\) 时,\(|cnt_\uparrow\ -\ cnt_\downarrow|\ \leq\ 1\) 时先手必胜,否则如果 \(\uparrow\) 多则 \(L\) 必胜,\(\downarrow\) 多则 \(R\) 必胜。
感觉这部分可以手玩+打表。
现在问题就变成了有 \(-2,\ -1,\ 0,\ 1,\ 2\)\(sum\ >\ 0,\ =\ 0,\ <\ 0\) 的个数。即求 \([x^i](x^1\ +\ 1)^a(x^{-1}\ +\ 1)^b(x^2\ +\ 1)^c(x^{-2}\ +\ 1)^d\)
注意到 \([x^i](x^1\ +\ 1)^a(x^{-1}\ +\ 1)^b\ =\ \binom{a\ +\ b}{i\ +\ b},\ i\ \geq\ 0\),从组合意义来考虑就是选到的 \(b\) 点看作不选,没选到的看作选了。
总时间复杂度 \(O(\sum_{i\ =\ 1}^n\ a_i)\)

代码

#include <bits/stdc++.h>

#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif

using namespace std;

constexpr int mod = 998244353;

int main() {
	constexpr auto pow_mod = [&](int x, int n) {
		int y = 1;
		while(n) {
			if(n & 1) y = (long long) y * x % mod;
			x = (long long) x * x % mod;
			n >>= 1;
		}
		return y;
	};

	vector<int> fac(1000001), ifac(1000001), pw2(1000001);

	auto prepare = [&]() {
		static constexpr int N = 1e6;
		fac[0] = pw2[0] = 1;
		for (int i = 1; i <= N; ++i) fac[i] = (long long) fac[i - 1] * i % mod, pw2[i] = (pw2[i - 1] << 1) % mod;
		ifac[N] = pow_mod(fac[N], mod - 2);
		for (int i = N; i; --i) ifac[i - 1] = (long long) ifac[i] * i % mod;
		return;
	};

	auto C = [&](int n, int m) { return (n < m || m < 0) ? 0 : (long long) fac[n] * ifac[m] % mod * ifac[n - m] % mod; };

	auto solve = [&]() {
		int n, pos_1 = 0, pos_2 = 0, neg_1 = 0, neg_2 = 0, star = 0, up = 0, down = 0, zero = 0;
		cin >> n;
		while(n--) {
			string s; int x;
			cin >> s >> x;
			if(s == "LL_RR" || s == "LRL_R" || s == "L_RLR") star += x;
			else if(s == "L_LRR") up += x;
			else if(s == "LLR_R") down += x;
			else if(s == "LR_RL") neg_1 += x;
			else if(s == "RL_LR") pos_1 += x;
			else if(s == "LRRL_" || s == "RLRL_" || s == "RRL_L") pos_2 += x;
			else if(s == "_RLLR" || s == "_RLRL" || s == "R_RLL") neg_2 += x;
			else zero += x;
		}

		vector<int> f1(pos_1 + neg_1 + 1);
		int z1 = neg_1;
		for (int i = 0; i <= pos_1; ++i) f1[z1 + i] = C(pos_1 + neg_1, i + neg_1);
		for (int i = 1; i <= neg_1; ++i) f1[z1 - i] = C(pos_1 + neg_1, i + pos_1);
		for (int i = 1; i < f1.size(); ++i) f1[i] = (f1[i] + f1[i - 1]) % mod;

		auto F1 = [&](int l, int r) {
			l = max(l, -neg_1);
			r = min(r, pos_1);
			if(l > r) return 0;
			l += z1; r += z1;
			return !l ? f1[r] : (f1[r] - f1[l - 1]) % mod;
		};

		int l_win = 0, r_win = 0, first_win = 0, second_win = 0, zero_coef = 0;
		for (int i = 0; i <= pos_2; ++i) {
			int t = C(pos_2 + neg_2, i + neg_2);
			l_win = ((long long) F1(1 - i * 2, pos_1) * t + l_win) % mod;
			r_win = ((long long) F1(-neg_1, -1 - i * 2) * t + r_win) % mod;
			zero_coef = ((long long) F1(-i * 2, -i * 2) * t + zero_coef) % mod;
		}
		for (int i = 1; i <= neg_2; ++i) {
			int t = C(pos_2 + neg_2, i + pos_2);
			l_win = ((long long) F1(1 + i * 2, pos_1) * t + l_win) % mod;
			r_win = ((long long) F1(-neg_1, -1 + i * 2) * t + r_win) % mod;
			zero_coef = ((long long) F1(i * 2, i * 2) * t + zero_coef) % mod;
		}
		l_win = ((long long) l_win * pw2[star + up + down + zero] % mod + mod) % mod;
		r_win = ((long long) r_win * pw2[star + up + down + zero] % mod + mod) % mod;
		zero_coef = ((long long) zero_coef * pw2[zero] % mod + mod) % mod;

		vector<int> fdown(down + 1);
		for (int i = 0; i <= down; ++i) fdown[i] = C(down, i);
		for (int i = 1; i <= down; ++i) fdown[i] = (fdown[i - 1] + fdown[i]) % mod;

		auto Fdown = [&](int l, int r) {
			l = max(l, 0);
			r = min(r, down);
			if(l > r) return 0;
			return !l ? fdown[r] : (fdown[r] - fdown[l - 1]) % mod;
		};
		
		for (int star_cnt = 0; star_cnt < 2; ++star_cnt) {
			int star_coef = 0;
			for (int i = 0; i <= star; ++i) if((i & 1) == star_cnt) star_coef = (C(star, i) + star_coef) % mod;
			star_coef = (long long) star_coef * zero_coef % mod;
			for (int i = 0; i <= up; ++i) {
				int t = C(up, i);
				if(!star_cnt) {
					l_win = ((long long) Fdown(0, i - 1) * t % mod * star_coef + l_win) % mod;
					r_win = ((long long) Fdown(i + 1, down) * t % mod * star_coef + r_win) % mod;
					second_win = ((long long) Fdown(i, i) * t % mod * star_coef + second_win) % mod;
				}
				else {
					l_win = ((long long) Fdown(0, i - 2) * t % mod * star_coef + l_win) % mod;
					r_win = ((long long) Fdown(i + 2, down) * t % mod * star_coef + r_win) % mod;
					first_win = ((long long) Fdown(i - 1, i + 1) * t % mod * star_coef + first_win) % mod;
				}
			}
		}

		l_win = (l_win + mod) % mod;
		r_win = (r_win + mod) % mod;
		first_win = (first_win + mod) % mod;
		second_win = (second_win + mod) % mod;
		cout << l_win << ' ' << r_win << ' ' << first_win << ' ' << second_win << endl;
		return;
	};

	prepare();
	int T, TC;
	cin >> T >> TC;
	while(TC--) solve();
	return 0;
}
posted @ 2018-11-04 22:04  King_George  阅读(167)  评论(0编辑  收藏  举报