zoukankan      html  css  js  c++  java
  • BZOJ 2281: [Sdoi2011]黑白棋 (Nim游戏+dp计数)

    题意

    这题目有一点问题,应该是在n个格子里有k个棋子,k是偶数.从左到右一白一黑间隔出现.有两个人不妨叫做小白和小黑.两个人轮流操作,每个人可以选 1~d 枚自己颜色的棋子,如果是白色则只能向右移动,如果是黑色只能向左移.移动过程中不能越过其他棋子.每个棋子的移动步数是任意的.不能操作的人就算输.求先手必胜的初始局面数模109+710^9+7的值.

    分析

    我们把k2frac k2每一对黑白棋之间的距离看作一堆石子,那么问题就转化为了有k2frac k2堆石子,每次可以选1...d1...d堆石子,每一堆随意取多少,没有石子取的算输.

    我们把问题转换为总方案减去先手必败的方案.我们先考虑假设每一堆石子只有一个,那么必败状态是?没错,就是石子堆数%(d+1)=0的状态.因为先手不管拿1~d的多少,另一个人都可以拿若干石子使得两人拿的石子数加起来等于(d+1)
    那么当每一堆石子不止一个时,把k2frac k2堆石子的石子数用二进制表示,统计每位上的1的个数,若每位上1的个数%(d+1)全为0,则必败.

    所以说我们就可以DP了.用f[i][j]f[i][j]表示在二进制中满足了前ii位的1的个数%(d+1)都为0,石子数为jj的方案数.转移时只用枚举一下这一位上的1的个数是(d+1)的x倍就可以转移了.转移时乘上C(k2,x(d+1))C(frac k2,x*(d+1)),表示在k2frac k2堆石子中选哪些来放1.石子数确定了,但在格子上的位置还没有确定,最后还要乘上每个白棋放在哪里.

    CODE

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    namespace READ {
    	inline void read(int &num) {
    		char ch; while((ch=getchar())<'0'||ch>'9');
    		for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
    	}
    }
    using namespace READ;
    typedef long long LL;
    const int MAXN = 10005;
    const int LOG = 15;
    const int mod = 1e9+7;
    int N, K, D;
    LL f[LOG][MAXN], fac[MAXN], inv[MAXN];
    inline void Pre() {
    	fac[0] = fac[1] = inv[0] = inv[1] = 1;
    	for(int i = 2; i <= N; ++i) inv[i] = 1ll * (mod - mod/i) * inv[mod%i] % mod;
    	for(int i = 2; i <= N; ++i) fac[i] = fac[i-1] * i % mod, inv[i] = inv[i-1] * inv[i] % mod;
    }
    inline LL C(int n, int m) {
    	if(m > n) return 0;
    	return fac[n] * inv[m] % mod * inv[n-m] % mod;
    }
    int main () {
    	read(N), read(K), read(D), Pre(); K>>=1;
    	f[0][0] = 1;
    	for(int i = 0, bit = 1; i < LOG-1; ++i, bit<<=1)
    		for(int j = 0; j <= N-(K<<1); ++j) if(f[i][j])
    			for(int x = 0; x*(D+1) <= K && j+x*(D+1)*bit <= N-(K<<1); ++x)
    				f[i+1][j+x*(D+1)*bit] = (f[i+1][j+x*(D+1)*bit] + f[i][j] * C(K, x*(D+1))) % mod;
    	LL ans = C(N, K<<1);
    	for(int i = 0; i <= N-(K<<1); ++i) ans = (ans - f[LOG-1][i] * C(N-K-i, K)) % mod;
    	printf("%lld
    ", (ans + mod) % mod);
    }
    
  • 相关阅读:
    Props VS State
    Component VS PureComponent
    Webpack loaders
    近期需要学习的技术
    jQuery源码解读三选择器
    jQuery源码解读二(apply和call)
    jQuery源码解读一
    Web语义化
    如何用python语言撸出图表系统
    抓取android系统日志_记录一次定位app闪退故障
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039400.html
Copyright © 2011-2022 走看看