思路:
之前模拟赛的一道题
当时在硬刚T1的正解,而没有写暴力
考虑局面没有石子堆是1的情况
那么显然只考虑总数的奇偶就可以判断答案了
因为必胜方拼命合并石子堆,必败方即使把一个堆减到1个石子,也会被必胜方拿走(就只有这一个石子时)或合并到另一个堆中去
所以局面除此之外只会被石子数为1的堆所影响(它被直接拿掉实际上是一步完成了合并,拿走两步操作)
设f[x][y]表示有x个石子数为1的堆,石子数大于1的堆的石子总数为y
通过记忆化搜索解决问题
注意状态转移时要细致讨论
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int T,n,m;
int f[55][50055],a[50055];
bool vis[55][50055];
int in()
{
int t=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
int dfs(int x,int y)
{
if (!vis[x][y]) vis[x][y]=1;
else return f[x][y];
if (y==1) return f[x][y]=dfs(x+1,0);
if (x-1>=0&&!dfs(x-1,y)) return f[x][y]=1;
if (x-2>=0&&!dfs(x-2,y+2+(y>0))) return f[x][y]=1;
if (y>1&&!dfs(x,y-1)) return f[x][y]=1;
if (x-1>=0&&y&&!dfs(x-1,y+1)) return f[x][y]=1;
return 0;
}
main()
{
memset(vis,0,sizeof(vis));
for (T=in();T;--T)
{
n=in();
int x=0,y=0;
for (int i=1;i<=n;++i)
{
a[i]=in();
if (a[i]==1) ++x;
else y+=a[i]+1;
}
if (y) --y;
dfs(x,y);
if (f[x][y]) puts("YES");
else puts("NO");
}
}