Codeforces Round #652 (Div. 2) F.BareLee(博弈)

题目

t(1<=t<=1e5)轮比赛,第一轮比赛主人公先手, 

第i轮比赛给出si,ei(1<=si<=ei<=1e18),si为初始的值,ei为终止局面的值,

对于当前为a的值,操作的一方可以将其变成a+1或2a,

若一方操作之后,当前的数大于ei,则操作的这个人输,

第i轮输的人会在第i+1轮先手,t轮过后,最后一轮的胜负情况是整个局面的胜负情况

问,先手是否有策略最后一轮必胜,先手是否有策略最后一轮必败,输出1/0(能/不能)

思路来源

AlexPanda的B站讲解

自己之前做过的eoj原题https://blog.csdn.net/Code92007/article/details/100734299

题解

eoj原题是初始si=1,ei=n(n<=1e18),每次变成2*a或a+1,问是否先手必胜/必败

可以通过对n的值sg打表找规律,对本题不适用,因为本题有个si

本题中可以用logn的方法将ei的值递归小,其方法对那道题也适用

一、首先,考虑能否先手必胜,

(1)若e为奇,可以O(1)判出

s为奇,先手败,因为先手只能操作到小于e的偶态,从而后手操作到奇态

s为偶,先手胜,

(2)考虑若e为偶,此处用[v]表示v的值向下取整,

①若[e/2]<s<=e,则两边的操作者只能加1,若s也为偶,先手败;若s为奇,先手胜

②若[e/4]<s<=[e/2],由于(e/2,e]且为偶时先手败,所以这个范围的s可以直接选择*2转移,此时先手必胜

③若s<=[e/4],则(s,e)能否先手胜,等价于询问(s,e/4)能否先手胜,

考虑(s,e/4)局面获胜者为主人公,对手的操作使得当前值v已经落在(e/4,e/2]中,

此时主人公只要按(2)②步骤的策略,即可先手必胜,拿下(s,e)的局面

 

二、考虑能否先手必败,也就是先手操作了之后,后手面临的局面是必胜的,

(1)若[e/2]<s<=e,此时先手直接*2,即必败

(2)若s<=[e/2],则(s,e)能否先手败,等价于询问(s,e/2)能否先手胜,

考虑(s,e/2)的局面获胜者为主人公,对手的操作使得当前值v已经落在(e/2,e]中,

此时主人公按(1)的作死策略即可完成先手必败

 

三、考虑n轮的情形,

如果在第一轮,

先手既可以控制先手必胜,也可以控制先手必败,即可通过倒推实现后续比赛的胜负自由取值,此时break

否则如果既不能控制先手必胜,也不能控制先手必败,说明对手可以任意控制,也break

否则,如果只能控制一个,就拖入下一轮继续考虑,

每次考虑的都是先手能否胜/败,

如果在上一轮是winner的话,把本轮算出的答案取反,代表本轮是后手

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10;
typedef long long ll;
int t,win,lose,sec;//想赢 想输 后手
ll s,e;
bool dfs(ll x,ll y){
    if(y&1){
        if(x&1)return 0;
        else return 1;
    }
    if(x>y/2){
        if(x&1)return 1;
        else return 0;
//        return (x-y)%2;
    }
    if(x>y/4){
        return 1;
    }
    return dfs(x,y/4);//x<=y/4
}
bool dfs2(ll x,ll y){
    if(x>y/2){
        return 1;
    }
    return dfs(x,y/2);
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&s,&e);
        win=dfs(s,e);
        lose=dfs2(s,e);
        win^=sec;lose^=sec;//若后手 取反
        sec=win;
        if(win==lose)break;
    }
    printf("%d %d\n",win,lose);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值