[博弈论] [计数] P5363 [SDOI2019] 移动金币

posted on 2024-05-30 05:56:10 | under | source

\(p_1\dots p_m\) 表示金币的位置,\(1\le p\le n\)

转化题意,令 \(a_i=p_i-p_{i-1}-1\),那么 \(p\)\(a\) 两两对应。

最终局势即 \(\forall a_i=0\),一次操作为 \(a_i-k,a_{i+1}-k\)

这是个阶梯 nim,先手必胜当且仅当 \(a_{m}\bigoplus a_{m-2}\bigoplus a_{m-4}\dots\ne 0\)

总集是 \(\rm C(n,m)\)。计算反集,按位考虑,则每一位上 \(a_m,a_{m-2},a_{m-4}\dots\)\(1\) 的个数必为偶数。并且 \(0\le \sum a\le n-m\)

容易有简单 \(\rm dp\),记 \(f_{i,j}\) 表示前 \(j\) 为总和是 \(i\) 时的反集总数,\(m\prime=\lceil \frac m2\rceil\),转移:

\[f_{i,j}=f_{i-c2^j,j-1}\times \rm C(m\prime,k)\times C(m-m\prime,c-k) \]

其中 \(c2^j\le i,k\le c\)

注意到后半部分与 \(i,j\) 无关,可以预处理得出。复杂度 \(O(nm\log n)\)

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define MOD(a) (((a) < 0) ? ((a) + mod) : (a))
const int N = 1e5 + 5e4 + 5, M = 55, mod = 1e9 + 9;
int n, m, _m, f[N], _f[N], jc[N], jcinv[N], ans;
int cc[M];

inline int qstp(int a, int k) {int res = 1; for(; k; a = a * a % mod, k >>= 1) if(k & 1) res = res * a % mod; return res;}
inline void init() {jc[0] = jcinv[0] = 1; for(int i = 1; i < N; ++i) jcinv[i] = qstp(jc[i] = jc[i - 1] * i % mod, mod - 2);}
inline int C(int n, int m) {return n < m ? 0 : jc[n] * jcinv[m] % mod * jcinv[n - m] % mod;}
signed main(){
	init();
	cin >> n >> m, _m = ((m + 1) >> 1);
	for(int c = 0; c <= m; ++c)
		for(int k = 0; k <= c; k += 2)
			cc[c] = (cc[c] + C(_m, k) * C(m - _m, c - k) % mod) % mod;
	f[0] = 1;
	for(int k = 0, base = 1; k <= 17; ++k, base <<= 1)
		for(int i = 0; i <= n - m; ++i){
			_f[i] = f[i], f[i] = 0;
			for(int c = 0; i - base * c >= 0 && c <= m; ++c)
				f[i] = (f[i] + _f[i - base * c] * cc[c] % mod) % mod;
		}
	ans = C(n, m);
	for(int i = 0; i <= n - m; ++i) ans = MOD(ans - f[i]);
	cout << ans;  	
	return 0;
}
posted @ 2026-01-12 20:07  Zwi  阅读(0)  评论(0)    收藏  举报