1. 程式人生 > >【BZOJ1115】[POI2009]石子遊戲Kam 階梯博弈

【BZOJ1115】[POI2009]石子遊戲Kam 階梯博弈

namespace 初始 nim class mic nim遊戲 mil mes data

【BZOJ1115】[POI2009]石子遊戲Kam

Description

有N堆石子,除了第一堆外,每堆石子個數都不少於前一堆的石子個數。兩人輪流操作每次操作可以從一堆石子中移走任意多石子,但是要保證操作後仍然滿足初始時的條件誰沒有石子可移時輸掉遊戲。問先手是否必勝。

Input

第一行u表示數據組數。對於每組數據,第一行N表示石子堆數,第二行N個數ai表示第i堆石子的個數(a1<=a2<=……<=an)。 1<=u<=10 1<=n<=1000 0<=ai<=10000

Output

u行,若先手必勝輸出TAK,否則輸出NIE。

Sample Input

2
2
2 2
3
1 2 4

Sample Output

NIE
TAK

題解:%一發別人的題解吧。

將所有堆的石子數差分,然後在一個堆中取石子相當於將這個堆中的石子移到後面的堆中去,這就變成了一個階梯博弈的模型。

階梯博弈:n堆石子,每次可以將在一堆石子中取若幹個移動到前面一堆中去,不能操作者輸。

結論:第偶數堆石子是沒有用的,因為你怎麽移對面就能怎麽移,所以相當於在奇數堆中玩NIM遊戲。

本題就是一個倒過來的階梯博弈。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int n,s;
int v[1010],c[1010];
void work()
{
	scanf("%d",&n),s=0;
	int i;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&v[i]),c[i]=v[i]-v[i-1];
		if((n-i+1)&1)	s^=c[i];
	}
	if(s)	printf("TAK\n");
	else	printf("NIE\n");
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)	work();
	return 0;
}

【BZOJ1115】[POI2009]石子遊戲Kam 階梯博弈