【NOI2015模拟YDC】游戏
2016-04-27 19:54
225 查看
Description
有一个有n个格子的东西,其中有一些格子中有棋子。每一次先手可以选择一个棋子移到它右边第一个没有棋子的位置。先占领格子n的玩家获胜。求先手必胜的方案数。n<=10^9,棋子数<=10^6
Solution
首先,让我们来看一看一次操作的本质。它相当于把一段连续的棋子向右移动了一格。
然后,我们要把这个游戏转化为我们熟悉的游戏。
“对于一段连续的棋子,我们可以把任意数量的从右开始的连续的棋子向右移动一格”
阶梯nim!
很明显,如果n-2有棋子,那么都不会有人动它。
那么,我们从n-2开始,是第0层。然后遇到一段连续的棋子,就把这一层加上这一段的棋子数,并且跳过这一段左边的那个空白。
如果只遇到空白,就把层数+1.
这样,我们就可以用朴素做法了。
但是这道题并不是判输赢,而是求方案数?
没事,移动之后sg=0就好了。
Code
#include<cstdio> #include<cstring> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define N 1000005 using namespace std; int a ,b ,c ,d ,n,m,t,sg,ans; int main() { scanf("%d%d",&m,&n); fo(i,1,n) scanf("%d",&a[i]); if (a ==m-1) { for(int i=n;a[i-1]+1==a[i];i--) t=i-1; printf("%d",n-t+1);return 0; } a[n+1]=m-1;a[0]=-1; for(int i=n;i;) { int j=i;t+=a[i+1]-a[i]-1; while (a[j-1]+1==a[j]) j--; if (t%2) b[++b[0]]=i-j+1; else if (t) { c[++c[0]]=i-j+1; if (a[i]+2==a[i+1]) d[c[0]]=b[b[0]]; } i=j-1; } fo(i,1,b[0]) sg^=b[i]; if (!sg) {printf("0");return 0;} fo(i,1,b[0]) if ((b[i]^sg)<=b[i]) ans++; fo(i,1,c[0]) if ((d[i]^sg)<=d[i]+c[i]&&(d[i]^sg)>d[i]) ans++; printf("%d",ans); }
相关文章推荐
- JavaScript求数组中的最大值和最小值
- 云计算相关概念储备
- android---防止ListView数据错乱的方法
- 从datetimepicker 将时间上传到access数据库中的代码
- android---自定义数字选择器
- [dfs序 树状数组] BZOJ 4034 [HAOI2015]T2
- 【游戏】23 款高格调游戏,活跃你的脑细胞
- Java RMI 框架(远程方法调用)
- 一对一与对多
- MySQL解释--百度百科
- android---HttpPost访问服务器
- android---HttpGet访问服务器
- java spring代码通用结构-java
- Linux命令大全
- android---ScrollView中嵌套ListView
- RelativeLayout_布局
- Android ImageButton,Button,CheckBox等抢了原有View的点击事件 点击事件冲突问题
- android---后台代发短信
- C# 事务异常TransactionScope处理
- android---service的启动,和activity的通信