Live2D

bzoj3895: 取石子(博弈论,记忆化搜索)

3895: 取石子

Time Limit: 1 Sec  Memory Limit: 512 MB
Submit: 361  Solved: 177
[Submit][Status][Discuss]

Description

Alice和Bob两个好朋含友又开始玩取石子了。游戏开始时,有N堆石子
排成一排,然后他们轮流操作(Alice先手),每次操作时从下面的规则中任选一个:
·从某堆石子中取走一个
·合并任意两堆石子
不能操作的人输。Alice想知道,她是否能有必胜策略。
 

 

Input

第一行输入T,表示数据组数。
对于每组测试数据,第一行读入N。
接下来N个正整数a1,a2…an,表示每堆石子的数量。
 

 

Output

对于每组测试数据,输出一行。
输出YES表示Alice有必胜策略,输出NO表示Alice没有必胜策略。
 

 

Sample Input

3
3
1 1 2
2
3 4
3
2 3 5

Sample Output

YES
NO
NO

HINT

 

100%的数据满足T<=100,  N<=50. ai<=1000

 

 

思路:

本来想纯粹博弈论,结果发现最终有的情况数不确定,所以只能搜索一波

因为无论何时,只要每堆都有石子,合并的结果都一样

所以我们把每一堆石子都先取成1

然后剩下这么多堆为1的石子,,每次操作有两种选择,要么合并,要么取走这一堆

然后就结束了

维护选用记忆化搜索

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define rii register int i
using namespace std;
int n,dp[55][50055],t,x,l,r,bj[55][50055];
int dplast(int l,int r)
{
    if(l==0)
    {
        return r&1;
    }
    if(r==1)
    {
        return dplast(l+1,0);
    }
    if(bj[l][r])
    {
        return dp[l][r];
        bj[l][r]=1;
    }
    if(l&&!dplast(l-1,r))
    {
        return dp[l][r]=1;
    }
    if(l&&r&&!dplast(l-1,r+1))
    {
        return dp[l][r]=1;
    }
    if(l>=2&&!dplast(l-2,r+2+(r?1:0)))
    {
        return dp[l][r]=1;
    }
    if(r&&!dplast(l,r-1))
    {
        return dp[l][r]=1;    
    }
    return dp[l][r]=0;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        l=0;
        r=-1;
        for(rii=1;i<=n;i++)
        {
               scanf("%d",&x);
              if(x==1)
            {
                l++;
               }
               else
            {
                r+=x+1;
            }
            if(r==-1)
            {
                r=0;
            }
        }
        if(dplast(l,r)==1)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
}

 

posted @ 2018-08-02 09:18  ztz11  阅读(548)  评论(0编辑  收藏  举报