1. 程式人生 > >BZOJ 1115: [POI2009]石子遊戲Kam (階梯nim)

BZOJ 1115: [POI2009]石子遊戲Kam (階梯nim)

limit solved sub log 一道 def ret cst 否則

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1138 Solved: 697
[Submit][Status][Discuss]

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

HINT

感謝MT大牛翻譯.

Source

又是一道很神的題

題目中給出的序列是嚴格上升的,所以我們可以考慮對整個序列差分一邊

然後我們再考慮拿走石子對答案個貢獻

拿走石子實際上是減小與前面的差值,增大與後面的差值

這實際上就是一個反方向的階梯nim遊戲!

然後倒著把奇數層異或起來就好啦

#include<cstdio>
#include
<queue> #include<cstring> #include<algorithm> using namespace std; const int MAXN=1e6+10,INF=1e9+10; inline char nc() { static char buf[MAXN],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++; } inline int read() {
char c=nc();int x=0,f=1; while(c<0||c>9){if(c==-)f=-1;c=nc();} while(c>=0&&c<=9){x=x*10+c-0;c=nc();} return x*f; } int a[MAXN]; main() { #ifdef WIN32 freopen("a.in","r",stdin); #else #endif int QWQ=read(); while(QWQ--) { int N=read(),ans=0; for(int i=1;i<=N;i++) a[i]=read(); for(int i=N;i>=2;i--) a[i]=a[i]-a[i-1]; for(int i=N;i>=1;i--) if( (N-i+1)&1 ) ans=ans^a[i]; puts(ans?"TAK":"NIE"); } return 0; }

BZOJ 1115: [POI2009]石子遊戲Kam (階梯nim)