题解 P3480 【[POI2009]KAM-Pebbles】
设a[i]表示第i堆石子的个数,c[i]表示a[i]-a[i-1],则我们每堆可以拿的石子数即为c[i]。当我们在第i堆拿了x个时,c[i]变成了c[i]-x,c[i+1]变成了c[i+1]+x,相当于我们把第i堆中可拿的石子转移到了i+1堆,由此我们可以把此题转化为一道反着的阶梯nim游戏。
下面简单讲解一下阶梯nim,如果不懂的话可以去网上搜一下。
阶梯nim是指,有n堆石子,每次我们可以从第i堆的石子中拿走一部分放到第i-1堆中,或者把第1堆中的石子拿走一部分,无法操作的人算输。先说结论:阶梯nim的游戏结果与只看奇数堆的石子数的普通nim结果相同。
假设我先手,那么我可以按照必胜策略把奇数堆中的石子转移到偶数堆,当对方拿的时候我们分情况讨论:
-
对方拿奇数堆中的石子到偶数堆,相当于进行对于奇数堆的普通nim,我们继续按照必胜策略拿奇数堆中的石子;
-
对方把偶数堆的石子拿到奇数堆,则我们可以把这部分石子继续向下拿,对于奇数堆相当于局势没有变动。
以上,我们简单证明了阶梯nim与奇数堆普通nim的等价。下面贴上渣代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int u;
int n;
int a[10004];
int c[10004];
int main()
{
scanf("%d",&u);
while(u--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
c[i]=a[i]-a[i-1];
int ans=0;
for(int i=n;i>=1;i-=2)
ans^=c[i];
if(ans)printf("TAK\n");
else printf("NIE\n");
}
return 0;
}
一定要注意这道题是从第i堆拿到第i+1堆,所以要反着跑阶梯nim!!