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;
}
原文地址:https://www.cnblogs.com/Narh/p/9405998.html