2281: [Sdoi2011]黑白棋

Time Limit: 3 Sec  Memory Limit: 512 MB
Submit: 626  Solved: 390
[Submit][Status][Discuss]

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。

Source

很有意思的一道博弈题,可惜HZWER学长给出了反例。

那么这一题通过手玩可以发现,最终状态必定是所有棋子全部扎堆在棋盘左端或右端,棋子之间没有间隙。不过仔细观察可以发现,可能在游戏状态中会出现所有棋子扎堆但不在棋盘一端的情况,其实那个时候就已经决定了最终的胜负。因为只要一方朝自己来的方向走了,则另一方必定能也往那边走一步,最终会步步紧逼直到走到棋盘一端。

根据这一点,感性理解一下,这个游戏就是一个把对方棋子“怼”过去的过程,谁怼赢了就是胜者。所以从一开始双方都一定拼尽全力往对面怼,所以有一个结论:先手不可能往左走,后手不可能往右走。

这样这个问题就变成了一个取石子游戏,每对相邻的白子和黑子之间的格子数是石子数(显然共有K/2堆石子),每人每次选不超过k堆取一个石子。

这个问题叫K-Nim,结论是:将所有石子数转成二进制,如果对于每一位二进制,这一位上为1的石子堆数都能被k+1整除则为必败态,否则为必胜态。

证明主要思路是: 1.最终态二进制每一位都为0必为必败态。2.只要有某位的1的个数不被k+1整除,则必然有一种走法使每一位都被整除。 3.如果每一位都被k+1整除,则无论怎么走都不可能使得每一位都仍然能被整除。

这三点分别保证了:最终态是必败态。必胜态必定能走到必败态。必败态只能走到必胜态。

详细证明:http://blog.csdn.net/weixinding/article/details/7321139

这样,我们分别用了“寻找最终态”和“模仿”的技巧将问题转化为了K-Nim问题。回到这一题,最终答案=总方案数-必败态的方案数。

设$f_{i,j}$表示前$i$个二进制位共放了$j$个石子的方案数,则$$ans=C_n^K-\sum_{i=0}^{n-K} f_{s,i}*C_{n-i-K/2}^{K/2}$$s为最高位的1,这里取15就够了。

考虑$f$的转移方程即可:$$f_{i+1,j+k*(d+1)*(1<<i)}\ \ +=\ \ f_{i,j}*C_{K/2}^{k*(d+1)}$$

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define rep(i,l,r) for (int i=l; i<=r; i++)
  5. typedef long long ll;
  6. using namespace std;
  7.  
  8. const ll N=,mod=;
  9. ll tot,ans,bin[],c[N][],f[][N];
  10. int n,K,d,p;
  11.  
  12. void add(ll &x,ll y){ x=(x+y)%mod; }
  13. void pre(){
  14. rep(i,,n) c[i][]=;
  15. rep(i,,n) rep(j,,min(*K,i)) c[i][j]=(c[i-][j]+c[i-][j-])%mod;
  16. }
  17. int C(int n,int m){ if (m>n-m) m=n-m; return c[n][m]; }
  18.  
  19. int main(){
  20. freopen("bzoj2281.in","r",stdin);
  21. freopen("bzoj2281.out","w",stdout);
  22. bin[]=; rep(i,,) bin[i]=bin[i-]<<;
  23. scanf("%d%d%d",&n,&K,&d); K>>=;
  24. pre(); f[][]=;
  25. rep(i,,) rep(j,,n-*K)
  26. for (int k=; k*(d+)<=K && j+k*(d+)*bin[i]<=n-*K; k++)
  27. add(f[i+][j+k*(d+)*bin[i]],f[i][j]*C(K,k*(d+)));
  28. rep(i,,n-*K) add(ans,f[][i]*C(n-i-K,K));
  29. tot=C(n,K*); printf("%lld\n",(tot-ans+mod)%mod);
  30. return ;
  31. }

[BZOJ2281][SDOI2011]黑白棋(K-Nim博弈)的更多相关文章

  1. BZOJ2281[Sdoi2011]黑白棋&BZOJ4550小奇的博弈——DP+nimk游戏

    题目描述 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色 ...

  2. BZOJ2281:[SDOI2011]黑白棋(博弈论,组合数学,DP)

    Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小 ...

  3. [SDOI2011]黑白棋 kth - nim游戏

    题面 题面 题解 观察题目,我们可以发现,这个游戏其实就是不断再把对方挤到一边去,也就是黑子不断往左走,白子不断往右走. 因此可以发现,如果将黑白子按顺序两两配对,那么它们中间的距离会不断缩小,且每次 ...

  4. BZOJ2281 [SDOI2011]黑白棋 【dp + 组合数】

    题目 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色棋子 ...

  5. bzoj2281 [Sdoi2011]黑白棋

    一眼$nimk$游戏,后来觉得不对劲,看了黄学长博客发现真的不是$nimk$. 就当是$nimk$做吧,那么我们要保证每一位上一的个数都是$d+1$的倍数. $dp$:$f[i][j]$表示从低到高第 ...

  6. 【BZOJ2281】[SDOI2011]黑白棋(博弈论,动态规划)

    [BZOJ2281][SDOI2011]黑白棋(博弈论,动态规划) 题面 BZOJ 洛谷 题解 先看懂这题目在干什么. 首先BZOJ上面的题面没有图,换到洛谷看题就有图了. 不难发现都相邻的两个异色棋 ...

  7. Bzoj 2281 [Sdoi2011]黑白棋 题解

    2281: [Sdoi2011]黑白棋 Time Limit: 3 Sec  Memory Limit: 512 MBSubmit: 592  Solved: 362[Submit][Status][ ...

  8. P2490 [SDOI2011]黑白棋

    P2490 [SDOI2011]黑白棋 题意 一个 \(1*n\) 的棋盘上,A 可以移动白色棋子,B 可以移动黑色的棋子,其中白色不能往左,黑色不能往右.他们每次操作可以移动 1 到 \(d\) 个 ...

  9. bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)

    黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...

随机推荐

  1. mybatis错误总结

    1:传递多个参数失败   Parameter 'username' not found. Available parameters are [0, 1, param1, param2] dao层错误写 ...

  2. 用java代码调用shell脚本执行sqoop将hive表中数据导出到mysql

    1:创建shell脚本 touch sqoop_options.sh chmod 777 sqoop_options.sh 编辑文件  特地将执行map的个数设置为变量  测试 可以java代码传参数 ...

  3. 天梯赛 L1-009 N个数求和 (模拟)

    本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数"分子/分母"的形式给出的,你输出的和也必须是有理数的形式. 输入格式: 输入第一行给出一个正整数N(<=1 ...

  4. Ajax+innerHTML+Dgls=好的用户体验+高性能+高效率

    为了引入Dgls,我们从创建Dom节点说起. 用JS创建Dom节点 var div = document.createElement('div'); div.className = 'gdls'; v ...

  5. php文件上传——php经典实例

     php文件上传——php经典实例 表单页 <html> <head> <title>文件上传</title> <meta charset='ut ...

  6. vscode中go插件配置

    # 转自:http://www.mamicode.com/info-detail-2436665.html # https://blog.csdn.net/bing2011/article/detai ...

  7. FPM定制RPM包

    安装FPM FPM是ruby写的打包工具,ruby版本要大于1.8.5 #安装ruby环境和gem包管理器 [root@test88 ~]# yum install -y ruby rubygems ...

  8. Linux/Unix 怎样找出并删除某一时间点的文件

    Linux/Unix 怎样找出并删除某一时间点的文件 在Linux/Unix系统中,我们的应用每天会产生日志文件,每天也会备份应用程序和数据库,日志文件和备份文件长时间积累会占用大量的存储空间,而有些 ...

  9. java之正则表达式、日期操作

    正则表达式和日期操作 正则表达式简介 正则表达式就是使用一系列预定义的特殊字符来描述一个字符串的格式规则,然后使用该格式规则匹配某个字符串是否符合格式要求. 作用:比如注册邮箱,邮箱有用户名和密码,一 ...

  10. PHP 执行系统外部命令的函数- system() exec() passthru()

    PHP 执行系统外部命令的函数: system() exec() passthru()区别:system() 输出并返回最后一行shell结果.exec() 不输出结果,返回最后一行shell结果,所 ...