【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 }
时间: 2024-07-30 18:33:41

【bzoj2281】[Sdoi2011]黑白棋的相关文章

[BZOJ2281][SDOI2011]黑白棋(K-Nim博弈)

2281: [Sdoi2011]黑白棋 Time Limit: 3 Sec  Memory Limit: 512 MBSubmit: 626  Solved: 390[Submit][Status][Discuss] Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色棋子,小B可以移动黑色的棋子,他们每次操作可以移动1到d个棋子. 每

[Sdoi2011]黑白棋 题解

2281: [Sdoi2011]黑白棋 Time Limit: 3 Sec  Memory Limit: 512 MBSubmit: 592  Solved: 362[Submit][Status][Discuss] Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色棋子,小B可以移动黑色的棋子,他们每次操作可以移动1到d个棋子. 每

【bzoj2281】 Sdoi2011—黑白棋

http://www.lydsy.com/JudgeOnline/problem.php?id=2281 (题目链接) 题意 一个1*n的棋盘,棋盘上一个隔一个的放着个黑棋和白棋,最左端是白棋,最右端是黑棋每次可以向左或向右移动<=d颗棋子,移动不能跨越棋子,也不能越出边界,问先手必胜的初始状态有多少. Solution Knim. 右转介绍:http://blog.csdn.net/weixinding/article/details/7321139 左转题解:http://blog.csdn

[SDOI2011]黑白棋

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

bzoj 2281: [Sdoi2011]黑白棋

再次,,,,,虚(一开始看错题了,看成一次移动一个棋子,能移动1-d个格子...这样的话有没有大神会做??本蒟蒻就教) 额,,直接%%%%把...http://hzwer.com/5760.html 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<map> 5 #include<queue> 6 #define N 1000005 7 #define

游戏开发(三)——WIN32 黑白棋(三)——游戏画面的现实

整个游戏分3部分介绍. 1.棋局的现实 2.AI的现实 3.游戏画面的现实 提供一下完整项目下载 这是第三部分:画面的显示 这部分其实就比较简单的,说白了就是api的堆砌. 主要了解下windows的消息机制,以及怎么画图 主要是分别封装了下对棋盘,棋子,以及当前轮到谁,当前比分是多少,就是游戏画面上不同的部分的绘制. void DrawReversiBoard(); void DrawReversiPieces(EnumReversiPiecesType type, int row_y, in

人机对战-黑白棋

先大致了解一下黑白棋: 规则 如果玩家在棋盘上没有地方可以下子,则该玩家对手可以连下.双方都没有棋子可以下时棋局结束,以棋子数目来计算胜负,棋子多的一方获胜. 在棋盘还没有下满时,如果一方的棋子已经被对方吃光,则棋局也结束.将对手棋子吃光的一方获胜. 翻转棋类似于棋盘游戏"奥赛罗 (Othello)",是一种得分会戏剧性变化并且需要长时间思考的策略性游戏. 翻转棋的棋盘上有 64 个可以放置黑白棋子的方格(类似于国际象棋和跳棋).游戏的目标是使棋盘上自己颜色的棋子数超过对手的棋子数.

黑白棋游戏 (codevs 2743)题解

[问题描述] 黑白棋游戏的棋盘由4×4方格阵列构成.棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子.这16枚棋子的每一种放置方案都构成一个游戏状态.在棋盘上拥有1条公共边的2个方格称为相邻方格.一个方格最多可有4个相邻方格.在玩黑白棋游戏时,每一步可将任何2个相邻方格中棋子互换位置.对于给定的初始游戏状态和目标游戏状态,编程计算从初始游戏状态变化到目标游戏状态的最短着棋序列. [样例输入] 1111 0000 1110 0010 1010 0101 1010 0101 [样例输出] 4

枚举(黑白棋)

/*代码一:DFS+Enum*/ //Memory Time //240K 344MS //本题只要求输出翻转的次数,因此BFS或DFS都适用 #include<iostream> using namespace std; bool chess[6][6]={false};//利用的只有中心的4x4 bool flag; int step; int r[]={-1,1,0,0,0};//便于翻棋操作 int c[]={0,0,-1,1,0}; bool judge_all(void)//判断&