zoukankan      html  css  js  c++  java
  • 【题解】【BZOJ】BZOJ2281 黑白棋

    BZOJ2281 黑白棋

    BZOJ2281 黑白棋

    1 题外话

    博弈和DP不分家是吧

    2 sol

    由于先手不能左移,后手不能右移,那么如果两个棋子紧靠,双方都不能移动,且不影响其他棋子的移动。

    将白-黑之间的间隔视为石子,问题转换成在(n/2) 个石子堆中任取(1,2,...,d) 个石子堆,每个可以取任意个

    这是一个典型的k-nim问题,这里有详细阐述

    给出结论:必败态是把每堆石子转换为二进制后,其中每一位上为1的石子堆数都能被(d+1)整除

    那么我们设(f[i][j]) 表示考虑二进制前i位,放置了j个石头的方案数

    转移如下

    [f[i+1][j+k imes (d+1) imes 2^i]+=f[i][j]*C^{frac{K}{2}}_{k imes (d+1)}]

    总方案减去必败即为必胜

    3 code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    const int N=100010;
    const int mod=1000000007;
    
    inline void read(int &x) {
        x=0;
        int f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9') {
            if (ch=='-') {
                f=-1;
            }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') {
            x=x*10+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    
    
    int n,k,d;
    int C[N][210];
    int f[30][N];
    int bin[30];
    
    inline void pre() {
        for(int i=0;i<=n;i++) {
            C[i][0]=1;
        }
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=min(2*k,i);j++) {
                C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
            }
        }
        bin[0]=1;
        for(int i=1;i<=20;i++) {
            bin[i]=bin[i-1]<<1;
        }
    }
    
    inline int c(int n,int m) {
        if (m>n-m) {
            m=n-m;
        }
        return C[n][m];
    }
    
    signed main() {
        read(n),read(k),read(d);
        k/=2;
        pre();
        f[0][0]=1;
        for(int i=0;i<15;i++) {
            for(int j=0;j<=n-2*k;j++) {
                for(int g=0;g*(d+1)<=k&&j+g*(d+1)*bin[i]<=n-2*k;g++) {
                    f[i+1][j+g*(d+1)*bin[i]]+=f[i][j]*c(k,g*(d+1));
                    f[i+1][j+g*(d+1)*bin[i]]%=mod;
                }
            }
        }
        int ans=c(n,k*2);
        for(int i=0;i<=n-2*k;i++) {
            ans-=(f[15][i]*c(n-i-k,k))%mod;
            ans=((ans%mod)+mod)%mod;
        }
        ans=((ans%mod)+mod)%mod;
        printf("%lld
    ",ans);
        return 0;
    }
    

    Author: tt66ea

    Created: 2021-08-13 周五 11:25

    Validate

  • 相关阅读:
    Spring ContextLoaderListener
    判断整数是否是对称数
    jstl缺包时的报错
    Spring初始化日志
    C# 网络编程之最简单浏览器实现
    Java实现 蓝桥杯 算法训练 Anagrams问题
    Java实现 蓝桥杯 算法训练 出现次数最多的整数
    Java实现 蓝桥杯 算法训练 出现次数最多的整数
    Java实现 蓝桥杯 算法训练 字串统计
    Java实现 蓝桥杯 算法训练 字串统计
  • 原文地址:https://www.cnblogs.com/tt66ea-blog/p/15136533.html
Copyright © 2011-2022 走看看