zoukankan      html  css  js  c++  java
  • 【BZOJ2281】[SDOI2011]黑白棋(博弈论,动态规划)

    【BZOJ2281】[SDOI2011]黑白棋(博弈论,动态规划)

    题面

    BZOJ
    洛谷

    题解

    先看懂这题目在干什么。
    首先BZOJ上面的题面没有图,换到洛谷看题就有图了。
    不难发现都相邻的两个异色棋子放在一起的时候,此时的先手无论怎么动,后手直接把棋子靠上去,这样子一定是先手先无法移动。即先手必败。
    把相邻的黑白棋子配对,不难发现这个玩意就是一个(NimK)游戏了。
    考虑(NimK)游戏是怎么来的,即把每堆石子转为二进制之后,检查是否每一位上的棋子数量都是(K+1)的倍数,如果是,则先手必败。否则先手必胜。
    那么这样子可以(dp)了。
    (f[i][j])表示当前考虑到了二进制上的第(i)位,总共放了(j)个石子的先手必败的方案数。
    这样子用总的放置方案数减去必败的方案数就可以得到必胜的方案数了。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    #define MAX 10010
    #define MOD 1000000007
    void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
    int jc[MAX],jv[MAX],inv[MAX];
    int C(int n,int m){if(m>n)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
    int f[15][MAX],n,K,d,ans;
    int main()
    {
    	scanf("%d%d%d",&n,&K,&d);
    	n-=K;K>>=1;jc[0]=jv[0]=inv[0]=inv[1]=1;
    	for(int i=1;i<=n+K+K;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    	for(int i=2;i<=n+K+K;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=n+K+K;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    	f[0][0]=1;
    	for(int j=0;j<=13;++j)
    		for(int i=0;i<=n;++i)
    			if(f[j][i])
    				for(int k=0;k<=K;k+=d+1)
    					if(i+(1<<j)*k<=n)add(f[j+1][i+(1<<j)*k],1ll*f[j][i]*C(K,k)%MOD);
    	for(int i=0;i<=n;++i)add(ans,1ll*f[14][i]*C(n-i+K,K)%MOD);
    	ans=(C(n+2*K,2*K)+MOD-ans)%MOD;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    第三周动手动脑
    判断回文串
    补码&&反码&&原码小知识
    第二周课后学习作业&&动手动脑课后作业
    Topcoder Tian Ji‘s Horse Racing
    Dining kuangbin
    网络流算法
    kuangbin Doing Homework
    kuangbin Prime Path
    ZOJ4033 CONTINUE...?
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9904259.html
Copyright © 2011-2022 走看看