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

    博弈论---Nimk问题。 dp再搞搞。

    很容易看出,该游戏的终态是每两个棋子都紧靠着。当一颗棋子移动,另一方与该棋子对应的那一刻可以立即追上,使得仍旧紧靠,最终棋子动弹不得,游戏结束。

    还能看出,对于白色棋子(先手),往左走没有意义。因为黑子(后手)可以紧随其上使得两者距离不变。同理黑子只往左走。(黄学长貌似提出了反例?)

    所以,问题可以抽象为Nim,与传统Nim只能选1堆不同,你可以选1-d堆。

    这个拓展问题叫做Nimk问题。对于这种问题,我们可以证明:当将n堆棋子化为二进制,每一位上如果1的个数mod(k+1)==0 则为必败态。

    详细证明,大传送术!http://blog.csdn.net/weixinding/article/details/7321139

    最后只需要计算方案数。使用dp,dp[i][j]表示当前在二进制第i位上,总计用了j石头的方案。转移方程为:

    dp[i+1][j+a*(k+1)*bin[i]]+=dp[i][j]*C(n,a*(k+1));

    注意组合数处理,取%等细节即可。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mo 1000000007
     4 #define N 10005
     5 #define LL long long
     6 LL c[N][205],dp[20][N],ans;
     7 int n,k,d,K,bin[20];
     8 void pre(){
     9     bin[0]=1; for(int i=1;i<=15;i++) bin[i]=bin[i-1]<<1;
    10     for(int i=0;i<=n;i++) c[i][0]=1;
    11     for(int i=1;i<=n;i++)
    12     for(int j=1;j<=min(i,K);j++)
    13     c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
    14 }
    15 LL C(int n,int m){
    16     if(n-m<m) m=n-m;
    17     return c[n][m];
    18 }
    19 LL cal(LL& x,LL y){
    20     x=(x+y)%mo;
    21 }
    22 int main(){
    23     scanf("%d%d%d",&n,&K,&d); pre(); dp[0][0]=1;
    24     for(int i=0;i<15;i++)
    25     for(int j=0;j<=n-K;j++)
    26     for(int k=0;k*(d+1)<=K/2 && j+k*(d+1)*bin[i]<=n-K;k++)
    27     cal(dp[i+1][j+k*(d+1)*bin[i]],dp[i][j]*C(K/2,k*(d+1)));
    28     for(int i=0;i<=n-K;i++)
    29     cal(ans,dp[15][i]*C(n-i-K/2,K/2));
    30     LL tot=C(n,K);
    31     cout<<(tot-ans+mo)%mo;
    32     return 0;
    33 }
  • 相关阅读:
    Andorid中写文件后在电脑上看不到的解决办法
    【Android布局】在程序中设置android:gravity 和 android:layout_Gravity属性
    OpenCV入门学习笔记
    视频播放(iOS开发)
    音频播放(iOS开发)
    iPad开发(相对于iPhone开发时专有的API)
    静态库/内存分析/通讯录/换肤/硬件信息获取
    Alpha冲刺! Day1
    软工团队
    软工团队
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/5953207.html
Copyright © 2011-2022 走看看