zoukankan      html  css  js  c++  java
  • bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)

    黑白棋(game

    【问题描述】

    小A和小B又想到了一个新的游戏。

    这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色。

    最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同。

    小A可以移动白色棋子,小B可以移动黑色的棋子,他们每次操作可以移动1到d个棋子。

    每当移动某一个棋子时,这个棋子不能跨越两边的棋子,当然也不可以出界。当谁不可以操作时,谁就失败了。

    小A和小B轮流操作,现在小A先移动,有多少种初始棋子的布局会使他胜利呢?

    【输入格式】

    共一行,三个数,n,k,d。

    【输出格式】

    输出小A胜利的方案总数。答案对1000000007取模。

    【样例输入】

    10 4 2

    【样例输出】

    182

    【数据规模和约定】

    对于30%的数据,有 k=2。

    对于100%的数据,有1<=d<=k<=n<=10000, k为偶数,k<=100。

    【思路】

           博弈+组合计数

           将相邻黑白点看作是一堆石子,则问题转化为Nimk游戏,即有n堆石子每次可以在1~d堆中拿出任意不为0个数的石子,什么时候局面必胜。

           结论:当且仅当nim和中1的个数为d+1的倍数,有局面必败。每次最多只能使d个为0,先手不能转移到必败态 ,则后手可以通过操作获胜。

           补集转化,求先手必败的局面数。

           设f[i][j]表示nim和前i位中有j个的先手必败的方案数,枚举 d+1 的倍数转移:

                  f[i][j+k*(d+1)*(1<<i)]+=f[i][j]*C(K/2,k*(d+1))

           则最后答案为C(n,K)-sigma{ f[15][i]*C(n-i-K/2,K/2) }

    【代码】

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 
     5 typedef long long LL;
     6 const int N = 2*1e4+10;
     7 const int M = 2*1e2+10;
     8 const int MOD = 1e9+7;
     9 
    10 LL c[N][M],f[M][N];
    11 
    12 void get_c() {
    13     for(int i=0;i<N;i++) c[i][0]=1;
    14     for(int i=1;i<N;i++) {
    15         for(int j=1;j<=min(i,M-1);j++)
    16             c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;
    17     }
    18 }
    19 LL C(int n,int k) {
    20     if(k>n-k) k=n-k; return c[n][k];
    21 }
    22 
    23 int n,K,D;
    24 
    25 int main() {
    26     get_c();
    27     scanf("%d%d%d",&n,&K,&D);
    28     K>>=1;
    29     f[0][0]=1;
    30     for(int i=0;i<15;i++)
    31         for(int j=0;j<=n-2*K;j++)
    32             for(int k=0;k*(D+1)<=K && j+k*(D+1)*(1<<i)<=n-2*K;k++)
    33                 f[i+1][j+k*(D+1)*(1<<i)]=(f[i+1][j+k*(D+1)*(1<<i)]+f[i][j]*C(K,k*(D+1))%MOD)%MOD;
    34     LL ans=0;
    35     for(int i=0;i<=n-2*K;i++) 
    36         ans=(ans+f[15][i]*C(n-i-K,K)%MOD)%MOD;
    37     printf("%lld",(C(n,2*K)-ans+MOD)%MOD);
    38     return 0;
    39 }
  • 相关阅读:
    P5956[POI2017]Podzielno【数学】
    P6672[清华集训2016]你的生命已如风中残烛【结论】
    P5825排列计数【EGF,NTT】
    P3971[TJOI2014]Alice and Bob【贪心】
    P3244[HNOI2015]落忆枫音【dp】
    jquery 选中单选按钮的值
    jquery ajax 详解
    Common Lisp中的car和cdr
    publishing(android)
    Preparing for Release(发布前的准备)
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5219287.html
Copyright © 2011-2022 走看看