先不考虑 A, B。对于 C 类点,由于情况 1 可以自由决定石子堆数的奇偶性,所以自己可以选择下一个房间是先手还是后手,而这先手与后手中必定有一个是胜利的,所以 C 类点是全局必胜态。同理,由于 D 类点会将情况 1 交给对方,所以 D 类点是全局必败态。所以,第一个碰到的 C 类点或 D 类点,就决定了全局的输赢。
而在碰到 C, D 类点之前,我们会发现 A 类点完全无效,B 类点相当于是交换先后手。于是 Alice 想要获胜有两种可能:
第一个 ∃ai>1 的点是 C 类点,并且前面有偶数个 B 类点。
第一个 ∃ai>1 的点是 D 类点,并且前面有奇数个 B 类点。
(还有一种可能是完全没有 C, D 类点,全是 A, B 类点,注意特判)
设 A, B, C, D 类点,各有 a,b,c,d 个。
以计算第一种情况为例,先考虑放第一个 C 类点,然后再枚举前面有 i 个 B 类点,再将剩下的 B, C, D 类点都放在第一个 C 类点之后,最后再插入所有剩下的 A 类点。则有
ci=0∑b[imod2=0](ib)i!⋅(c+d−1+b−i)!⋅(n−a)!n!
(插入的方案数:若场上已经有 x 个点,则有 x+1 个空隙可以插入)
第二种情况同理。
时间复杂度 O(n+∑ki)。
一种简单粗暴的统计方法。
以计算第一种情况为例,先考虑将第一个 C 类点固定在位置 x,然后再枚举前面有 i 个 B 类点,则相当于是要选 x−1−i 个 A 类点和 i 个 B 类点放到位置 x 之前。位置 x 之前随便排列,位置 x 之后仍然随便排列,有
using s64 = longlong; using u64 = unsignedlonglong;
/* 取 min */ template <classT> inlinevoidchmin(T &x, const T &y){ if (x > y) { x = y; } } /* 取 max */ template <classT> inlinevoidchmax(T &x, const T &y){ if (x < y) { x = y; } }
/* ----- ----- ----- 正文 ----- ----- ----- */
constint mod = 1e9 + 7; // 模数需根据实际问题调整
/* 模意义下 加法 */ inlinevoidadd(int &x, constint &y){ x += y; if (x >= mod) { x -= mod; } }
/* 模意义下 减法 */ inlinevoiddec(int &x, constint &y){ x -= y; if (x < 0) { x += mod; } }
/* 模意义下 乘法 */ inlinevoidmul(int &x, constint &y){ x = 1ll * x * y % mod; }
/* 快速幂 */ intqpow(int a, int b, int p){ int ans = 1; for (; b; b >>= 1) { if (b & 1) ans = 1ll * ans * a % p; a = 1ll * a * a % p; } return ans; }
int n; int a, b, c, d;
structBinomCoef { std::vector<int> fact, facv;
voidinit(constint &n){ fact.resize(n + 1), facv.resize(n + 1); fact[0] = 1; for (int i = 1; i <= n; i ++) { fact[i] = 1ll * fact[i - 1] * i % mod; }
facv[n] = qpow(fact[n], mod - 2, mod); for (int i = n - 1; i >= 0; i --) { facv[i] = 1ll * facv[i + 1] * (i + 1) % mod; } }
intbinom(int n, int m){ if (n < m || m < 0) { return0; } return1ll * facv[m] * facv[n - m] % mod * fact[n] % mod; } } bc;
intcalc1(){ if (!c) return0; int ans = 0; for (int i = 0; i <= b; i ++) { if (i % 2 != 0) continue; int cur = 1ll * bc.binom(b, i) * bc.fact[i] % mod; cur = 1ll * cur * bc.fact[c + d - 1 + b - i] % mod; add(ans, cur); } ans = 1ll * ans * c % mod; ans = 1ll * ans * bc.fact[n] % mod * bc.facv[n - a] % mod; return ans; }
intcalc2(){ if (!d) return0; int ans = 0; for (int i = 0; i <= b; i ++) { if (i % 2 != 1) continue; int cur = 1ll * bc.binom(b, i) * bc.fact[i] % mod; cur = 1ll * cur * bc.fact[c + d - 1 + b - i] % mod; add(ans, cur); } ans = 1ll * ans * d % mod; ans = 1ll * ans * bc.fact[n] % mod * bc.facv[n - a] % mod; return ans; }