zoukankan      html  css  js  c++  java
  • Luogu P2490「JSOI2016」黑白棋

    我博弈基础好差..

    Luogu P2490


    题意

    有一个长度为$ n$的棋盘,黑白相间的放$ k$个棋子,保证$ k$是偶数且最左边为白子

    每次小$ A$可以移动不超过$ d$个白子,然后小$ B$可以移动不超过$ d$个黑子

    双方不能把棋子越过其他棋子

    求有多少种初始方案使得小$ A$先手必胜

    注意白子只能往右黑子只能往左


    $NimK游戏$

    对于一个局面,我们可以把每对相邻的(白,黑)对看成一堆石子,数量即为这两个棋子之间的距离

    问题等价于每次可以在不超过$ d$堆中取石子求是否必胜

    考虑普通的$ Nim$游戏相当于$ d=1$的情况,必败态为每堆的异或值为$ 0$

    推广到$ d>1$的情况就是二进制下每一位在所有石子堆中的出现次数均是$d+1$的倍数则必败

    这就是$NimK$游戏


    $ Solution$

    $ DP$

    设$ f_{i,j}$表示只考虑二进制前$i$位,由$ j$颗石子组成的必败态的方案数

    $ f_{i+1,j+s2^{i+1}(d+1)}+=f_{i,j}*inom{k/2}{s(d+1)}$  

    意义是选出若干堆在这一位上有$ 1$且乘上选这些堆的方案数

    注意最后需要

    $ f_{i,j}*=inom{n-k/2-i}{k/2}$

    其意义是给这些堆石子在原棋盘上定位

    然后就做完了


    $ my code$

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #define p 1000000007
    #define rt register int
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x = 0; char zf = 1; char ch = getchar();
        while (ch != '-' && !isdigit(ch)) ch = getchar();
        if (ch == '-') zf = -1, ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    int i,j,k,m,n,x,y,z,cnt;
    int f[15][40010];
    int C[10010][205];
    int main(){
        C[0][0]=1;
        n=read();k=read();int d=read();
        for(rt i=1;i<=n;i++){
            C[i][0]=1;
            for(rt j=1;j<=i&&j<=k;j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
        }
        
        for(rt i=0;i*(d+1)<=k/2;i++)
        f[0][i*(d+1)]=C[k/2][i*(d+1)];
        for(rt i=0;i<=13;i++)
        for(rt j=0;j<=n;j++){
            for(rt s=0;s<=k&&j+(1<<i+1)*s<=n;s+=d+1)
            (f[i+1][j+(1<<i+1)*s]+=1ll*f[i][j]*C[k/2][s]%p)%=p;
        }
        int ans=C[n][k];
        for(rt i=0;n-k/2-i>=0;i++)
        f[13][i]=1ll*f[13][i]*C[n-k/2-i][k/2]%p,(ans-=f[13][i])%=p;
        cout<<(ans+p)%p;
        return 0;
    }
  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10069074.html
Copyright © 2011-2022 走看看