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;
}