题目连接ios
首先这是一个阶梯博弈。spa
咱们将金币两两组合,若是对方移动前一个,那么咱们把后一个移动相同的距离,局面至关于没有变化。若是对方移动后一个,就至关于\(NIM\)游戏中,取走了一些石子。code
因此这个游戏也就是金币两两组合后,有\(\lceil \frac{m}{2}\rceil\) 堆石子,进行\(NIM\)游戏游戏
统计方案get
而后考虑如何统计方案。string
根据上面的结论。也就是咱们要找出\(\lceil \frac{m}{2}\rceil\)堆石子,使他们个数异或和为0。it
\(f[i][j]\)表示异或和的前i位异或起来为\(0\),已经有了j个石子的方案数。io
就有以下的转移\[f[i][j]=\sum\limits_{k=0}^{2 ^{2k}\le j\&k\le \lceil\frac{m}{2}\rceil}{f[i-1][j-2^{2k}]\times (^{\lceil \frac{m}{2} \rceil}_{2k})}\]ast
而后再考虑这\(\lceil \frac{m}{2} \rceil\)堆石子的位置。class
利用隔板法。就至关于把\(\frac{m}{2}\)个挡板插到了长度为\(n-i\)(i为所放的石子长度)的序列里。
/* * @Author: wxyww * @Date: 2019-05-11 18:24:32 * @Last Modified time: 2019-05-15 09:49:57 */ #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<ctime> using namespace std; typedef long long ll; const int N = 150000 + 100,mod = 1e9 + 9; #define int ll ll read() { ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x*f; } int inv[N],f[20][N],jc[N]; int qm(int x,int y) { int ret = 1; for(;y;y >>= 1,x = 1ll * x * x % mod) if(y & 1) ret = 1ll * ret * x % mod; return ret; } int C(int x,int y) { return 1ll * jc[x] * inv[y] % mod * inv[x - y] % mod; } signed main() { int n = read(),m = read(); //预处理 jc[0] = 1; for(int i = 1;i <= n + m;++i) jc[i] = 1ll * jc[i - 1] * i % mod; inv[0] = 1; for(int i = 1;i <= n + m;++i) inv[i] = qm(jc[i],mod - 2); int ans = C(n,m); n -= m; int num = (m + 1) >> 1; //dp f[0][0] = 1; for(int i = 1;i <= 19;++i) { int z = i - 1; for(int j = 0;j <= n;++j) { for(int k = 0;(k << z) <= j && k <= num;k += 2) { f[i][j] += 1ll * f[i - 1][j - (k << z)] * C(num,k) % mod; f[i][j] %= mod; } } } //统计答案 for(int i = 0;i <= n;++i) { ans -= 1ll * f[19][i] * C(m / 2 + n - i,m / 2) % mod; ans = (ans + mod) % mod; } cout<<ans; return 0; }