vijos2055 移動金幣

題目連接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;
}
相關文章
相關標籤/搜索