題目連接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; }