bzoj 3895 取石子——博弈论
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3895
看题解:https://blog.csdn.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=55,M=1005; int T,n,a[N],dp[N][N*M+N]; int rdn() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar(); return ret; } bool dfs(int x,int y) { if(y==1)x++,y=0;//! if(dp[x][y]!=-1)return dp[x][y]; if(!x) return dp[x][y]=(y&1); if(x&&!dfs(x-1,y))return dp[x][y]=1; if(x&&y&&!dfs(x-1,y+1))return dp[x][y]=1;//&&y! if(x>1&&!dfs(x-2,y?y+3:y+2))return dp[x][y]=1; if(y&&!dfs(x,y-1))return dp[x][y]=1; return dp[x][y]=0; } int main() { T=rdn(); memset(dp,-1,sizeof dp); while(T--) { n=rdn();int cnt=0,sum=0; for(int i=1;i<=n;i++) { a[i]=rdn(); if(a[i]==1)cnt++;else sum+=a[i]; } puts(dfs(cnt,(n-cnt)?(n-cnt-1+sum):0)?"YES":"NO");//判n-cnt! } return 0; }