jzoj3819 [NOI2015模拟9.9]取石子

66 篇文章 0 订阅

Description


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

30% T<=10,N<=5,ai<=3
60% T<=100,N<=20,ai<=100
100% T<=4000,N<=50,ai<=1000

Solution


这种类规律题可以先从简单情况想起。对于一堆的情况胜负由奇偶性决定,两堆可以看成是一堆加上一个石子(合并操作)
继续往下会出现问题,对于1颗石子的堆,在取走后只减少了1步操作,即0颗石子的堆不能合并。那么分别记录1颗石子的堆数、剩下不为1的石子操作数的总和。n这么小直接爆搜,担心过不了就记忆化

操作分别有合并两个1的堆、合并1和另一个不为1的堆、取走一个1、取走不为1的堆中的一个

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int N=50005;

int rec[405][N];
int cnt,sum,n;

int dfs(int a,int b) {
    if (!a) return b&1;
    if (b==1) return dfs(a+1,b-1);
    if (rec[a][b]!=-1) return rec[a][b];
    if (a&&!dfs(a-1,b)) return rec[a][b]=1;
    if (a&&b&&!dfs(a-1,b+1)) return rec[a][b]=1;
    if (a>=2&&!dfs(a-2,b+2+(b!=0))) return rec[a][b]=1;
    if (b&&!dfs(a,b-1)) return rec[a][b]=1;
    return rec[a][b]=0;
}

int main(void) {
    memset(rec,-1,sizeof(rec));
    int T; scanf("%d",&T);
    while (T--) {
        scanf("%d",&n);
        cnt=0; sum=-1;
        rep(i,1,n) {
            int x; scanf("%d",&x);
            if (x==1) cnt++;
            else sum+=x+1;
        }
        if (sum==-1) sum=0;
        if (!dfs(cnt,sum)) puts("NO");
        else puts("YES");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值