一本通1668取石子

1668:取石子

时间限制: 1000 ms         内存限制: 524288 KB

【题目描述】

Alice 和 Bob 两个好朋友又开始玩取石子了。游戏开始时,有 NN 堆石子排成一排,然后他们轮流操作(Alice 先手),每次操作时从下面的规则中任选一个:

1、从某堆石子中取走一个;

2、合并任意两堆石子。

不能操作的人输。Alice 想知道,她是否能有必胜策略。

【输入】

第一行输入 T,表示数据组数。

对于每组测试数据,第一行读入 N;

接下来 N 个正整数 a1,a2,,an,表示每堆石子的数量。

【输出】

对于每组测试数据,输出一行。

输出 YES 表示 Alice 有必胜策略,输出 NO 表示 Alice 没有必胜策略。

【输入样例】

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

【输出样例】

YES
NO
NO

【提示】

数据范围与提示:

对于全部数据,T100,N50,ai1000

 

sol:貌似和博弈论没有半毛钱关系

如果没有1的堆,那么判断一下总操作数的奇偶性即可,烦就烦在有1,

题解上说是记搜,分四种情况(具体见注释),不知道为什么n=50都能过qaq

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=55;
int T;
int n,A[N];
int Bo[N][N*1000];
inline bool dfs(int Num1,int Step)
{
    if(Bo[Num1][Step]!=-1) return Bo[Num1][Step];
    if(Num1==0) return Bo[Num1][Step]=((Step&1)?1:0);
    if(Step==1) return Bo[Num1][Step]=dfs(Num1+1,0);
    if(Num1&&(!dfs(Num1-1,Step))) return Bo[Num1][Step]=1; //取走一个1
    if(Num1>=2&&(!dfs(Num1-2,Step+2+(Step?1:0)))) return Bo[Num1][Step]=1; //合并两个1
    if(Num1&&Step&&(!dfs(Num1-1,Step+1))) return Bo[Num1][Step]=1; //把一个1合并到非1堆中
    if(Step&&(!dfs(Num1,Step-1))) return Bo[Num1][Step]=1; //合并两个大堆或取走一个
    return Bo[Num1][Step]=0;
}
int main()
{
    R(T);
    memset(Bo,-1,sizeof Bo);
    while(T--)
    {
        int i,Sum=-1,cnt=0;
        R(n);
        for(i=1;i<=n;i++)
        {
            A[i]=read();
            if(A[i]==1) cnt++;
            else Sum+=A[i]+1;
        }
        if(!cnt)
        {
            if(Sum&1) puts("YES");
            else puts("NO");
            continue;
        }
        Sum=max(Sum,0);
        if(dfs(cnt,Sum)) puts("YES");
        else puts("NO");
    }
    return 0;
}
/*
input3
5
3
2 1 3 
4
1 1 1 1 
2
1 3 
5
1 2 1 2 2 
3
1 1 1
output
YES
YES
YES
NO
NO
*/
View Code

 

转载于:https://www.cnblogs.com/gaojunonly1/p/10554797.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值