洛谷P8382 [POI2004] Gra

这道题是暂无评定

题目描述

让我们考虑一个在 m \times 1m×1 的板子上玩的游戏,板子被从 11 到 mm 编号。

现在板子上有 nn 个棋子,每个都严格占据板子上的一个格子,没有一个棋子占据格子 mm。

每个单独的移动遵循以下原则:移动的人选择一个棋子把它移动到比它大的格子中第一个未被占据的格子里去。两个选手交替移动,谁先占据格子 mm 谁赢。

我们在当且仅当他移动以后令一选手无论如何都无法赢他的时候说当前选手的移动称作 \text{winning}winning 操作。

我们想知道先手有多少个移动是 \text{winning}winning 操作。

输入格式

第一行有两个数 m,nm,n 。

然后接下来 nn 个上升的整数表示初始被占据的格子编号。

输出格式

输出先手有多少移动是 \text{winning}winning 操作。

 输入输出样例

输入 #1    输出 #1
5 2        1
1 3

 

对于 100100 % 的数据:2 \le m \le 10^{9}, 1 \le n \le 10^{6}2≤m≤109,1≤n≤106 ,且有 n + 1 \le mn+1≤m 。

下面是一个例子:

在 m = 7m=7 的时候,一个选手可以把 22 移到 44,把 33 移到 44 或者把 66 移动到 77。

代码:

#include<cstdio>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define N 1000005
using namespace std;
int read(){
	int x=0,f=1,ch=getchar();
	for(;!isdigit(ch);ch=getchar()) f=(ch=='-')?-1:1;
	for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
	return x*f;}
void print(int x){
	if(x<0) putchar('-'),x=~(x-1);
	if(x>9) print(x/10);
	putchar(x%10+48);}
int n,m,a[N],tot,b[N],SG,cnt;
void init(){
	m=read(),n=read();
	for(int i=1;i<=n;++i) a[i]=read();
	if(a[n]==m-1){
		for(int i=n;i>=1 && a[n]-a[i]==n-i;--i,++cnt);
		print(cnt);
		exit(0);
	}
}
void CoreCode(){
	for(int i=1;i<=n;++i){
		a[i]=m-1-a[i]-(n-i+1);
		if(!a[i]) break;
		if(i==1 || a[tot]>a[i]) a[++tot]=a[i];
		++b[tot];
	}
	for(int i=1;i<=tot;++i){
		if(a[i]&1){
			SG^=b[i];
		}
	}
	for(int i=1;i<=tot;++i){
		if(a[i]&1){
			if((SG^b[i])<b[i]) ++cnt;
		}
		else{
			int lst=i<tot && a[i+1]==a[i]-1?b[i+1]:0;
			if((SG^lst)>lst && (SG^lst)<=lst+b[i]) ++cnt;
		}
	}
	print(cnt);
}
int main(){
	init();
	CoreCode();
	return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值