JZOJ2368 【SDOI2011】黑白棋
题目
题目大意
在一个1*n的棋盘上,有黑棋和白棋交错分布,每次,一个人可以移动自己的ddd颗旗子。
问先手必胜的方案数。
思考历程
在一开始,我就有点要放弃的念头。
因为这题是一道博弈问题。
我是非常不擅长博弈类问题的。
但是其他的题有想不出来,于是只能硬是想了好久。
最终那了个部分分。
正解
这题正解当然跟博弈有一些关系。
首先,对于这题有一个隐藏的限制。
白棋不能向左移,黑棋不能向右移。
这是为什么?
我们可以感性理解一下(证明什么的我当然不会):
如果白棋左移,那么在它右边的黑棋可以模仿它的操作,也跟着左移。
同理,如果黑棋右移,那么在它左边的白棋也可以模仿他的动作,也跟着右移。
那么我们就可以发现,这样走是没有意义的。
然后我们就可以转换问题的模型:
可以将对应(相邻)的两个白棋和黑棋中间的距离当作石子。
那么就有K2\frac{K}{2}2K堆石子,然后每次可以在至多ddd堆石子,至少111堆石子中各自拿走一颗石子。
这个问题叫Nimk问题。
这又是个什么东西啊?
对于Nimk问题,我们有一个神奇的结论:将所有堆石子的个数化成二进制,每一位统计一下111的个数,如果个数都是d+1d+1d+1的倍数,那么这就是必败态。
如何证明?
我们可以感性理解一下:怎么又是感性理解……
先手只能拿走111到ddd堆中的石子,那么,后手可以故意的模仿,然后将两人取得的石子的总数固定在d+1d+1d+1。那么如果一直这么下去,后手必定会赢。
为什么要转成二进制呢?
我觉得,其实只要转成了二进制,那么后手就能保证每次能够取得这么多的石子,使得两个人取石子的总数为d+1d+1d+1。具体怎样解释,我觉得我还要好好理解一下,暂且感性感性吧(感性理解真是一个好东西)。
模型转换成了Nimk问题,让我们求先手必胜的方案数。
先手必胜的方案数等于总方案数减去先手必败的方案数。
如何求先手必败的方案数呢?
当然是DP。
设fi,jf_{i,j}fi,j表示在二进制的前iii位中,一共用了jjj颗石子的先手必败的方案数。
仔细想想这个状态没有任何问题,因为我们只需要保证在每一个二进制位上都满足它必败就好了。这样设状态之后转移就方便多了。
我们再枚举一个kkk(小写的kkk,不要混淆),表示一共有k∗(d+1)k*(d+1)k∗(d+1)堆石子下一个二进制位上为111。
转移?
fi+1,j+k∗(d+1)∗2i←fi,j∗CK2k∗(d+1)f_{i+1,j+k*(d+1)*2^i}\leftarrow f_{i,j}*C_{\frac{K}{2}}^{k*(d+1)}fi+1,j+k∗(d+1)∗2i←fi,j∗C2Kk∗(d+1)
注意:为了程序实现方便,在这个方程中,前iii位的最高位实际上是i−1i-1i−1位。这样的DP中,初始化直接是f0,0=1f_{0,0}=1f0,0=1
在一波DP之后,我们就可以统计答案了。
其实我们可以将其视为,在n−j−Kn-j-Kn−j−K个空中插入K/2K/2K/2个东西。
这个东西可以用组合数来搞一搞,那么就是Cn−j−K2K2C_{n-j-\frac{K}{2}}^{\frac{K}{2}}Cn−j−2K2K种方案,用它来乘上fMAXBIT,jf_{MAXBIT,j}fMAXBIT,j就好了。
然后这题就愉快地解决了。
复杂度表示懒得分析。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mo 1000000007
int n,K,d;
int C[10001][101];
int f[17][10001];
int main(){
scanf("%d%d%d",&n,&K,&d);
C[0][0]=1;
for (int i=1;i<=n;++i){
C[i][0]=1;
for (int j=1;j<=i && j<=K;++j)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo;
}
f[0][0]=1;
for (int i=0;i<15;++i)
for (int j=0;j<=n-K;++j)
if (f[i][j])
for (int k=0;k*(d+1)<=K>>1 && j+k*(d+1)*(1<<i)<=n-K;++k)
(f[i+1][j+k*(d+1)*(1<<i)]+=(long long)f[i][j]*C[K>>1][k*(d+1)]%mo)%=mo;
int ans=0;
for (int j=0;j<=n-K;++j)
ans=(ans+(long long)f[15][j]*C[n-j-(K>>1)][K>>1]%mo)%mo;
printf("%d\n",(C[n][K]-ans+mo)%mo);
return 0;
}
我认为这个程序实现不用注释。
总结
博弈类问题,可真是一个神奇东西啊!
然而,好多的我都不会严谨证明。
感性理解就好……
我觉得以后要多做一些博弈类问题。
JZOJ2368 【SDOI2011】黑白棋的更多相关文章
- 【BZOJ2281】[SDOI2011]黑白棋(博弈论,动态规划)
[BZOJ2281][SDOI2011]黑白棋(博弈论,动态规划) 题面 BZOJ 洛谷 题解 先看懂这题目在干什么. 首先BZOJ上面的题面没有图,换到洛谷看题就有图了. 不难发现都相邻的两个异色棋 ...
- [BZOJ2281][SDOI2011]黑白棋(K-Nim博弈)
2281: [Sdoi2011]黑白棋 Time Limit: 3 Sec Memory Limit: 512 MBSubmit: 626 Solved: 390[Submit][Status][ ...
- Bzoj 2281 [Sdoi2011]黑白棋 题解
2281: [Sdoi2011]黑白棋 Time Limit: 3 Sec Memory Limit: 512 MBSubmit: 592 Solved: 362[Submit][Status][ ...
- P2490 [SDOI2011]黑白棋
P2490 [SDOI2011]黑白棋 题意 一个 \(1*n\) 的棋盘上,A 可以移动白色棋子,B 可以移动黑色的棋子,其中白色不能往左,黑色不能往右.他们每次操作可以移动 1 到 \(d\) 个 ...
- bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)
黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...
- 【BZOJ2281】【博弈论+DP】 [Sdoi2011]黑白棋
Description 黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是 ...
- [SDOI2011]黑白棋
Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小 ...
- BZOJ 2281: [Sdoi2011]黑白棋 (Nim游戏+dp计数)
题意 这题目有一点问题,应该是在n个格子里有k个棋子,k是偶数.从左到右一白一黑间隔出现.有两个人不妨叫做小白和小黑.两个人轮流操作,每个人可以选 1~d 枚自己颜色的棋子,如果是白色则只能向右移动, ...
- 【bzoj2281】 Sdoi2011—黑白棋
http://www.lydsy.com/JudgeOnline/problem.php?id=2281 (题目链接) 题意 一个1*n的棋盘,棋盘上一个隔一个的放着个黑棋和白棋,最左端是白棋,最右端 ...
- BZOJ2281[Sdoi2011]黑白棋&BZOJ4550小奇的博弈——DP+nimk游戏
题目描述 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色 ...
随机推荐
- equal 与 hashCode
equal Object: public static boolean equals(Object a, Object b) { return (a == b) || (a != null & ...
- python多线程,event,互斥锁,死锁,递归锁,信号量
Python多线程/event 多线程-threading python的thread模块是⽐较底层的模块, python的threading模块是对thread做了⼀些包装的, 可以更加⽅便的被使⽤ ...
- MongoDB后台运行
文章目录 命令方式(推荐) 命令行和配置文件方式 命令行: 配置文件: 命令方式(推荐) 如果想在后台运行,启动时只需添加 --fork函数即可. fork: 以守护进程的方式运行MongoDB. 指 ...
- css3@media实现原理
window.matchMedia() 基本用法 window.matchMedia方法用来检查CSS的mediaQuery语句.各种浏览器的最新版本(包括IE 10+)都支持该方法,对于不支持该方法 ...
- Jodd - Java界的瑞士军刀轻量级工具包!
Jodd介绍 Jodd是对于Java开发更便捷的开源迷你框架,包含工具类.实用功能的集合,总包体积不到1.7M. Jodd构建于通用场景使开发变得简单,但Jodd并不简单!它能让你把事情做得更好,实现 ...
- Berlin Programming Contest 2004 Heavy Transportation /// dijkstra oj22604
题目大意: 输入t:t为样例数 每个样例输入n,m:n 为顶点个数 m 为路径数 接下来m行 每行输入 u v w :从 u 点到 v 点的路承重为 w 输出 车子若想通过 1~n的最短路 车重需限 ...
- shell脚本练习03--字符串
######################################################################### # File Name: -.sh # Author ...
- JS流程控制语句 继续循环continue continue的作用是仅仅跳过本次循环,而整个循环体继续执行。
继续循环continue continue的作用是仅仅跳过本次循环,而整个循环体继续执行. 语句结构: for(初始条件;判断条件;循环后条件值更新) { if(特殊情况) { continue; } ...
- Aria2 使用
没错,又是受够了迅雷.旋风的各种奇葩减速(哥哥我还买了了VIP!),IDM 对协议支持又太少还有事没事提示你不是正版三天两头闹着要更新.于是我想起来之前看到过的 Aria2,虽然之前也只是略有耳闻,但 ...
- 廖雪峰Java12maven基础-1maven入门-2依赖管理
maven 如果我们的项目依赖第三方的jar包: Commons Logging发布的jar包在那里下载? 使用Log4j需要哪些jar包 其他依赖:junit,Javamail,MySQL驱动... ...
