[POJ1740]A New Stone Game

題目

傳送門 to POJ

傳送門 to VJ

思路

有一個顯而易見的結論,如果我可以將其分成對稱的,那麼先手必敗。

比如,我們有 1,2,3,1,2,3\langle 1,2,3,1,2,3\rangle 的石子。顯然這是對稱的,那麼對手如何操作,我只要對稱的操作即可。

現在,我們考慮不對稱的情況。如果某些堆是不能配對的,那麼它們一定兩兩不相同。

我們來分類討論一下吧!——

  • 如果有奇數堆石子。

在數軸上將每一堆石子的數量點出來,大致就是

在這裏插入圖片描述
那麼,我把最大的那一堆用來填補紅色的部分,就可以變成兩兩匹配的情況。

填補完之後,顯然,這一堆還會剩下一些(在數軸上可以很直觀的看出,[0,max][0,\max] 是把紅色部分包含在內的,並且 max\max 和第二大之間至少有 11 的距離)。

剛好,把這些剩下的拿完,就滿足了拿石子的要求:至少拿走一個,然後分給別人一些。

  • 如果有偶數堆石子。

直接將數軸的原點設置爲 min\min 即可——將 max\max 轉變爲 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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章