bzoj 3895 取石子——博弈论

时间:2024-09-14 11:05:50

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3895

看题解:https://blog.****.net/popoqqq/article/details/43989101

虽然大于1的堆的操作次数带来的必胜或必败在还有等于1的堆存在的情况下就不准了,但仍可以把它先记录下来,因为一旦没有了等于1的堆,就会按那个取,所以它被加入考虑。

注意两点:1.传参时注意如果没有大于1的堆,别传入-1;

     2.注意当大于1的堆被取成一个等于1的堆时要判断。

dfs里写得美一点,就能快256ms。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=;
int T,n,a[N],dp[N][N*M+N];
int rdn()
{
int ret=;char ch=getchar();
while(ch>''||ch<'')ch=getchar();
while(ch>=''&&ch<='')(ret*=)+=ch-'',ch=getchar();
return ret;
}
bool dfs(int x,int y)
{
if(y==)x++,y=;//!
if(dp[x][y]!=-)return dp[x][y];
if(!x) return dp[x][y]=(y&);
if(x&&!dfs(x-,y))return dp[x][y]=;
if(x&&y&&!dfs(x-,y+))return dp[x][y]=;//&&y!
if(x>&&!dfs(x-,y?y+:y+))return dp[x][y]=;
if(y&&!dfs(x,y-))return dp[x][y]=;
return dp[x][y]=;
}
int main()
{
T=rdn();
memset(dp,-,sizeof dp);
while(T--)
{
n=rdn();int cnt=,sum=;
for(int i=;i<=n;i++)
{
a[i]=rdn();
if(a[i]==)cnt++;else sum+=a[i];
}
puts(dfs(cnt,(n-cnt)?(n-cnt-+sum):)?"YES":"NO");//判n-cnt!
}
return ;
}