[BZOJ2281][SDOI2011]黑白棋(K-Nim博弈)
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 2Sample Output
182HINT
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)}$$
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const ll N=,mod=;
ll tot,ans,bin[],c[N][],f[][N];
int n,K,d,p; void add(ll &x,ll y){ x=(x+y)%mod; }
void pre(){
rep(i,,n) c[i][]=;
rep(i,,n) rep(j,,min(*K,i)) c[i][j]=(c[i-][j]+c[i-][j-])%mod;
}
int C(int n,int m){ if (m>n-m) m=n-m; return c[n][m]; } int main(){
freopen("bzoj2281.in","r",stdin);
freopen("bzoj2281.out","w",stdout);
bin[]=; rep(i,,) bin[i]=bin[i-]<<;
scanf("%d%d%d",&n,&K,&d); K>>=;
pre(); f[][]=;
rep(i,,) rep(j,,n-*K)
for (int k=; k*(d+)<=K && j+k*(d+)*bin[i]<=n-*K; k++)
add(f[i+][j+k*(d+)*bin[i]],f[i][j]*C(K,k*(d+)));
rep(i,,n-*K) add(ans,f[][i]*C(n-i-K,K));
tot=C(n,K*); printf("%lld\n",(tot-ans+mod)%mod);
return ;
}
[BZOJ2281][SDOI2011]黑白棋(K-Nim博弈)的更多相关文章
- BZOJ2281[Sdoi2011]黑白棋&BZOJ4550小奇的博弈——DP+nimk游戏
题目描述 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色 ...
- BZOJ2281:[SDOI2011]黑白棋(博弈论,组合数学,DP)
Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小 ...
- [SDOI2011]黑白棋 kth - nim游戏
题面 题面 题解 观察题目,我们可以发现,这个游戏其实就是不断再把对方挤到一边去,也就是黑子不断往左走,白子不断往右走. 因此可以发现,如果将黑白子按顺序两两配对,那么它们中间的距离会不断缩小,且每次 ...
- BZOJ2281 [SDOI2011]黑白棋 【dp + 组合数】
题目 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色棋子 ...
- bzoj2281 [Sdoi2011]黑白棋
一眼$nimk$游戏,后来觉得不对劲,看了黄学长博客发现真的不是$nimk$. 就当是$nimk$做吧,那么我们要保证每一位上一的个数都是$d+1$的倍数. $dp$:$f[i][j]$表示从低到高第 ...
- 【BZOJ2281】[SDOI2011]黑白棋(博弈论,动态规划)
[BZOJ2281][SDOI2011]黑白棋(博弈论,动态规划) 题面 BZOJ 洛谷 题解 先看懂这题目在干什么. 首先BZOJ上面的题面没有图,换到洛谷看题就有图了. 不难发现都相邻的两个异色棋 ...
- 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个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...
随机推荐
- 【有上下界网络流】【ZOJ】2314 Reactor Cooling
[算法]有上下界网络流-无源汇(循环流) [题解]http://www.cnblogs.com/onioncyc/p/6496532.html //未提交 #include<cstdio> ...
- 支付宝Android接口4.0以上报错Failure calling remote service
很坑爹的问题,4.0一下没问题,完全按照接口文件写的.网上一查,很多人遇到.最好直接在4.2下调试,看看报错问题,然后度娘. 将RSA文件中的加上“BC”后测试通过...NND PKCS8Encode ...
- mysql查询日期相关的
今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ...
- 判断是否引入jquery
主要使用typeof检验 <script language="javascript"> if(typeof jQuery == 'undefined'){ window ...
- 通过jquery.validate.js校验表单字段是否合法
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...
- final关键字详解
java中,final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量).下面就从这三个方面来了解一下final关键字的基本用法. 1.修饰类 当用final修饰一个类时,表明这个类不能被继承 ...
- 爬虫实战--基于requests和beautifulsoup的妹子网图片爬取(福利哦!)
#coding=utf-8 import requests from bs4 import BeautifulSoup import os all_url = 'http://www.mzitu.co ...
- Wireshark抓包保存文件(图片,视频,音频等)
1.首先选择一个图片的分组 如图的9801 就是JPG 2.对下面的窗口里面选中JPEG File Interchange Format 右键选择 导出分组字节流 3.文件输入XXX.jpg,注意保存 ...
- shell将多行文本重定向到文件【转】
在shell中,使用Here Document方式将文本重定向到文件,格式如下: ( cat << EOF 要写的文本 EOF ) > 目标文件 示例test.sh: #! /bin ...
- Machine Learning系列--维特比算法
维特比算法(Viterbi algorithm)是在一个用途非常广的算法,本科学通信的时候已经听过这个算法,最近在看 HMM(Hidden Markov model) 的时候也看到了这个算法.于是决定 ...