BZOJ2281: [Sdoi2011]黑白棋
阿新 • • 發佈:2019-01-01
BZOJ2281: [Sdoi2011]黑白棋
https://lydsy.com/JudgeOnline/problem.php?id=2281
分析:
- \(nimk\)結論,先手必敗當且僅當對於每一位有1的石子堆數模(d+1)都等於0。
- 那麼把白棋到黑旗這段看成石子就可以直接用這個結論。
- 設\(f[i][j]\)表示考慮前\(i\)位,當前用了\(j\)個石子先手必敗的方案數。
- 轉移列舉有多少堆石子這一位是1.
程式碼:
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; typedef long long ll; #define mod 1000000007 #define N 100050 int n,K,d; ll fac[N],inv[N],f[20][10050]; ll qp(ll x,ll y) { ll re=1; for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod; return re; } ll C(int x,int y) { if(x<y) return 0; return fac[x]*inv[y]%mod*inv[x-y]%mod; } inline void upd(ll &x,ll y) { x=x+y; if(x>=mod) x-=mod; } int main() { scanf("%d%d%d",&n,&K,&d); int i,j,l; for(fac[0]=i=1;i<N;i++) fac[i]=fac[i-1]*i%mod; inv[N-1]=qp(fac[N-1],mod-2); for(i=N-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod; f[0][0]=1; for(i=0;i<16;i++) { for(j=0;j<=n-K;j++) if(f[i][j]) { for(l=0;l*(d+1)<=K/2&&(1<<i)*(d+1)*l+j<=n-K;l++) { upd(f[i+1][j+(1<<i)*l*(d+1)],f[i][j]*C(K/2,l*(d+1))%mod); } } } ll ans=C(n,K); for(i=0;i<=n-K;i++) { upd(ans,mod-f[16][i]*C(n-i-K/2,K/2)%mod); } printf("%lld\n",(ans+mod)%mod); }