【NOI2015模拟YDC】游戏

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[N],b[N],c[N],d[N],n,m,t,sg,ans;
int main() {
    scanf("%d%d",&m,&n);
    fo(i,1,n) scanf("%d",&a[i]);
    if (a[n]==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); 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值