[POJ1740]A New Stone Game / [SPOJ2021]Moving Pebbles

27 篇文章 0 订阅

题目

两个题的意思完全相同。

传送门 to POJ

传送门 to DarkBZOJ

思路

有一个显而易见的结论,如果我可以将其分成对称的,那么先手必败。

比如,我们有 ⟨ 1 , 2 , 3 , 1 , 2 , 3 ⟩ \langle 1,2,3,1,2,3\rangle 1,2,3,1,2,3 的石子。显然这是对称的,那么对手如何操作,我只要对称的操作即可。

现在,我们考虑不对称的情况。如果某些堆是不能配对的,那么它们一定两两不相同。

我们来分类讨论一下吧!——

  • 如果有奇数堆石子。

在数轴上将每一堆石子的数量点出来,大致就是

在这里插入图片描述
那么,我把最大的那一堆用来填补红色的部分,就可以变成两两匹配的情况。

填补完之后,显然,这一堆还会剩下一些(在数轴上可以很直观的看出, [ 0 , max ⁡ ] [0,\max] [0,max] 是把红色部分包含在内的,并且 max ⁡ \max max 和第二大之间至少有 1 1 1 的距离)。

刚好,把这些剩下的拿完,就满足了拿石子的要求:至少拿走一个,然后分给别人一些。

  • 如果有偶数堆石子。

直接将数轴的原点设置为 min ⁡ \min min 即可——将 max ⁡ \max max 转变为 min ⁡ \min min ,顺便填补其余的。

显然,利用原点 “吃掉” 一个点之后,剩下的就是奇数堆石子,与上面一样了。

  • 综上所述

只要不是两两匹配,就是先手胜,否则后手胜。

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
inline int readint(){
	int a = 0, f = 1; char c = getchar();
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(long long x){
	if(x < 0) putchar('-'), x = -x;
	if(x > 9) writeint(x/10);
	putchar((x%10)^48);
}

# define MB template < typename T >
MB void getMax(T &a,const T &b){ if(a < b) a = b; }
MB void getMin(T &a,const T &b){ if(b < a) a = b; }

const int MaxN = 201, infty = (1<<30)-1;
int a[MaxN], n;

int main(){
	while(scanf("%d",&n) != EOF){
		if(n == 0) break;
		for(int i=1; i<=n; ++i)
			a[i] = readint();
		sort(a+1,a+n+1), a[n+1] = infty;
		bool win = false;
		for(int i=1; i<=n and not win; i+=2)
			if(a[i] != a[i+1])
				win = true;
		printf("%d\n",win);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值