【SDOI 2009】E&D

【题目】

传送门

题目描述:

E 与小 W 进行一项名为 “E&D” 游戏。游戏的规则如下:

桌子上有 2 n 2n 堆石子,编号为 1 2 n 1\dots2n 。其中,为了方便起见,我们将第 2 k 1 2k-1 堆与第 2 k 2k 堆( 1 k n 1≤k≤n )视为同一组。第 i i 堆的石子个数用一个正整数 S i S_i 表示。

一次分割操作指的是,从桌子上任取一堆石子,将其移走。然后分割它同一组的另一堆石子,从中取出若干个石子放在被移走的位置,组成新的一堆。操作完成后,所有堆的石子数必须保证大于 0 0 。显然,被分割的一堆的石子数至少要为 2 2

两个人轮流进行分割操作。如果轮到某人进行操作时,所有堆的石子数均为 1 1 ,则此时没有石子可以操作,判此人输掉比赛。小 E 进行第一次分割。他想知道,是否存在某种策略使得他一定能战胜小 W 。因此,他求助于小 F,也就是你,请你告诉他是否存在必胜策略。

例如,假设初始时桌子上有 4 4 堆石子,数量分别为 1 , 2 , 3 , 1 1,2,3,1 。小 E 可以选择移走第 1 1 堆,然后将第 2 2 堆分割(只能分出 1 1 个石子)。接下来,小 W 只能选择移走第 4 4 堆,然后将第 3 3 堆分割为 1 1 2 2 。最后轮到小 E,他只能移走后两堆中数量为 1 1 的一堆,将另一堆分割为 1 1 1 1 。这样,轮到小 W 时,所有堆的数量均为 1 1 ,则他输掉了比赛。故小 E 存在必胜策略。

输入格式:

输入第一行是一个正整数 T T T 20 T≤20 ),表示测试数据数量。接下来有 T T 组数据。

对于每组数据,第一行是一个正整数 n n ,表示桌子上共有 n n 堆石子。其中,输入数据保证 n n 是偶数。

第二行有 n n 个正整数 S 1 S n S_1\dots S_n ,分别表示每一堆的石子数。

输出格式:

输出包含 T T 行。对于每组数据,如果小 E 必胜,则输出一行 “YES”,否则输出 “NO”

样例数据:

输入
2
4
1 2 3 1
6
1 1 1 1 1 1

输出
YES
NO

备注:

【数据范围】

对于 20 % 20\% 的数据: n = 2 n = 2
对于另外 20 % 20\% 的数据: n 4 S i 50 n≤4;S_i≤50
对于 100 % 100\% 的数据: n 2 × 1 0 4 S i 2 × 1 0 9 n≤2×10^4;S_i≤2×10^9


【分析】

这道题可以换成 n 2 \frac{n}{2} 个子问题,求出每个子问题的 S G SG 函数值异或一下求值即可。

对于这道题,有两个性质:

  1. x x y y 都是奇数,则 S G ( x , y ) = 0 SG(x,y)=0
  2. 否则, S G ( x , y ) = S G ( x 2 , y 2 ) + 1 SG(x,y)=SG(\lceil\frac{x}{2}\rceil,\lceil\frac{y}{2}\rceil)+1

简单证一下第一个,第二个实在不会证(打表打出来的

证明: S G ( x , y ) SG(x,y) x x y y 均为奇数时为必败态。

此时,先手只能分割奇数,而用奇数一定会分割出一个偶数 x 1 x_1 和另一个奇数 y 1 y_1

后手的最优策略就是,舍去奇数,将 x 1 x_1 分割为 x 1 1 x_1-1 1 1 即可,那么先手只能分割 x 1 1 x_1-1 而这个数又是一个奇数,也就是说先手只能分割奇数,后手只能分割偶数,那么最后一定是后手分割 2 2 ,变为 1 1 1 1 ,此时先手输。


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int SG(int x,int y)
{
	if((x&1)&&(y&1))  return 0;
	return SG((x+1)/2,(y+1)/2)+1;
}
int main()
{
	int n,i,T;
	scanf("%d",&T);
	while(T--)
	{
		int x,y,res=0;
		scanf("%d",&n);
		for(i=1;i<=n>>1;++i)
		{
			scanf("%d%d",&x,&y);
			res^=SG(x,y);
		}
		puts(res?"YES":"NO");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/87889705