版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
传送门
题解:
很容易注意到这是一个阶梯NIM,先手必胜当且仅当所有奇数位置上的石头数量的xor和不为 。
按照套路,考虑拆位,由于异或和不为 不太好算,考虑算异或和为 ,即奇数位置上每一位的数量都是偶数。
首先可以 处理出在某一位上一共放了 个 ,且奇数位置上的总数为偶数的方案数。
然后考虑两种DP,考虑前 位,当前总和为 的方案数,转移是 的。
但是实际上可以直接考虑设 表示考虑前 位,总和距离 还差 的方案数, 的上界显然不超过 。转移是 的,注意到是一个卷积,可以利用多项式乘法优化到 ,不过这道题由于 过小但卷积常数过大没什么用。
综上,这道题理论上是可以做到
的。可以拿来出毒瘤题了
给5000, 给1e18可能要开3s左右。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=1e9+9;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b){
int r=1;for(;b;b>>=1,a=mul(a,a))
if(b&1)r=mul(r,a);return r;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline void ex_gcd(int a,int b,int &x,int &y){
if(!b){x=1,y=0;return ;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}
inline int Inv(int a){
int x,y;ex_gcd(mod,a,y,x);
return x+(x>>31&mod);
}
cs int M=63;
int n,m;
int fac[M],ifac[M];
inline void init_fac(){
fac[0]=fac[1]=1;
for(int re i=2;i<M;++i)fac[i]=mul(fac[i-1],i);
ifac[M-1]=Inv(fac[M-1]);
for(int re i=M-1;i;--i)ifac[i-1]=mul(ifac[i],i);
}
inline int C(int n,int m){return n>=0&&m>=0&&n>=m?mul(fac[n],mul(ifac[m],ifac[n-m])):0;}
int f[M][M],g[M];
inline int work(int n,int m){
int od=m>>1,ev=m+1>>1;f[18][0]=1;
for(int re i=0;i<=m;++i)
for(int re j=0;j<=i;j+=2)Inc(g[i],mul(C(od,j),C(ev,i-j)));
for(int re i=17;~i;--i)
for(int re j=0;j<=m;++j)if(f[i+1][j])
for(int re li=(j*2)+(n>>i&1),k=std::max(0,li-m);k<=m&&k<=li;++k)
Inc(f[i][li-k],mul(f[i+1][j],g[k]));
return f[0][0];
}
inline int binom(int n,int m){int r=ifac[m];for(int re i=n;i>n-m;--i)Mul(r,i);return r;}
signed main(){
#ifdef zxyoi
freopen("coin.in","r",stdin);
#endif
scanf("%d%d",&n,&m);init_fac();
cout<<dec(binom(n,m),work(n-m,m+1));
return 0;
}