zoukankan      html  css  js  c++  java
  • bzoj2281 [Sdoi2011]黑白棋

    Description

    小A和小B又想到了一个新的游戏。
    这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色。
    最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同。
    小A可以移动白色棋子,小B可以移动黑色的棋子,他们每次操作可以移动1到d个棋子。
    每当移动某一个棋子时,这个棋子不能跨越两边的棋子,当然也不可以出界。当谁不可以操作时,谁就失败了。
    小A和小B轮流操作,现在小A先移动,有多少种初始棋子的布局会使他胜利呢?

    Input

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

    Output

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

    Sample Input

    10 4 2

    Sample Output

    182

    HINT

     1<=d<=k<=n<=10000, k为偶数,k<=100。

    正解:博弈论+$dp$。

    推荐博客:$nim$游戏及其变形

    首先题目似乎漏了一句话,就是白棋不能右移,黑棋不能左移。。

    因为每对黑白棋相邻,所以实际上我们可以转化一下模型,每对黑白棋就是一堆石子,它们的距离$-1$就是石子个数。

    现在每次可以取$d$个石子堆中的石子,问先手必胜的方案有多少?

    这是一个经典的$nim-k$问题,结论是对于石子堆的每一个二进制位,如果这一位上为$1$的石子堆数是$d+1$的倍数,那么先手必败。

    所以我们可以直接考虑先手必败的方案数,再用总方案数减去即可。

    设$f[i][j]$表示考虑到二进制从小到大的第$i$位,当前石子总数为$j$,先手必败的方案数。

    那么$f[i+1][j+p*(d+1)*2^{i}]+=f[i][j]*inom{k/2}{p*(d+1)}$,注意第二维必须$leq n-k$。

    最后我们枚举石子数$i$,那么$Ans-=f[15][i]*inom{n-k/2-i}{k/2}$,这里可以看成在合法位置中选择$k/2$个位置的方案数。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define rhl (1000000007)
     6 
     7 using namespace std;
     8 
     9 int c[10005][105],f[16][10005],n,k,d,ans;
    10 
    11 il int gi(){
    12   RG int x=0,q=1; RG char ch=getchar();
    13   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    14   if (ch=='-') q=-1,ch=getchar();
    15   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    16   return q*x;
    17 }
    18 
    19 il int C(RG int n,RG int m){
    20   return n<m ? 0 : c[n][min(m,n-m)];
    21 }
    22 
    23 int main(){
    24 #ifndef ONLINE_JUDGE
    25   freopen("chess.in","r",stdin);
    26   freopen("chess.out","w",stdout);
    27 #endif
    28   n=gi(),k=gi(),d=gi(),c[0][0]=1;
    29   for (RG int i=1;i<=n;++i){
    30     c[i][0]=1;
    31     for (RG int j=1;j<=k && j<=i;++j){
    32       c[i][j]=c[i-1][j-1]+c[i-1][j];
    33       if (c[i][j]>=rhl) c[i][j]-=rhl;
    34     }
    35   }
    36   f[0][0]=1,ans=C(n,k);
    37   for (RG int i=0;i<15;++i)
    38     for (RG int j=0;j<=n-k;++j)
    39       for (RG int p=0,q;p*(d+1)<=(k>>1);++p){
    40     q=j+p*(d+1)*(1<<i); if (q>n-k) break;
    41     f[i+1][q]=(1LL*f[i][j]*C(k/2,p*(d+1))+f[i+1][q])%rhl;
    42       }
    43   for (RG int i=0;i<=n-k;++i){
    44     ans=(-1LL*f[15][i]*C(n-k/2-i,k/2)+ans)%rhl;
    45     if (ans<0) ans+=rhl;
    46   }
    47   cout<<ans; return 0;
    48 }
  • 相关阅读:
    Electron+Vue开发跨平台桌面应用
    html2canvas生成图片
    将某个DIV内容保存成图片,使用HTML2CANVAS截图方法(高清图并解决图片跨域问题)
    css3实现动画效果完整代码demo
    Vue + element从零打造一个H5页面可视化编辑器——pl-drag-template
    Vue.Draggable学习总结
    3d学习网
    vue router 报错: Uncaught (in promise) NavigationDuplicated {_name:""NavigationDuplicated"... 的解决方法
    网页适配 iPhoneX,就是这么简单
    关于for循环
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7999312.html
Copyright © 2011-2022 走看看