CF1369F-BareLee【博弈论,SG函数】

1|0正题

题目链接:https://www.luogu.com.cn/problem/CF1369F


1|1题目大意

T次游戏,每次给出一个st,两个人轮流操作,可以让s=s+1或者s=s×2,如果s>t的话那个人就输了。

每次输的人将作为下一次的先手,最后一把决定胜负。

求第一次先手的人是否有必胜/必败策略。

1st1018,1T105


1|2解题思路

先考虑一把里面是否有必胜策略,考虑用SG函数去求,因为我们只需要维护SG0和不为0的信息就好了。

如果一个状态不能走到任何0状态那么这个节点就是0状态,为了方便,后面的SG=2都视为SG=1

首先t2+1t这个范围中因为×2用不了,所以这个范围肯定是01交错的。

然后考虑从t2开始往前每个状态都会额外指向一个乘二后的值,如果也就是前面01交错中每次跳两个,所以要么指向的都是0要么指向的都是1,如果指向的都是0,那么后面就有一段都是1,否则如果指向的是1显然不会产生影响,依旧是01交错。

然后让t继续除二,然后考虑如果后面是连续1段我们不需要考虑任何东西,如果后面是01交错就继续按照前面的做,直到到这段包括s我们就可以得到sSG值了。

然后考虑必败,最后一步肯定是×2,所以我们直接让t=t2,然后看是否必胜,这就是能否必败的答案了。

然后反过来dp一次就可以得到答案了。

时间复杂度:O(Tlogt)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e5+10; ll n,p[N][2],f[N][2]; bool check(ll s,ll t){ bool now=0,k=0;ll r=t; while(t/2>=s){ if(now)now=0,r=t/2; else now=k^!(t&1); t/=2;k=(r-t)&1; } return now|((r-s)&1); } signed main() { scanf("%lld",&n); for(ll i=1,s,t;i<=n;i++){ scanf("%lld%lld",&s,&t); p[i][0]=check(s,t); if(t/2>=s)p[i][1]=check(s,t/2); else p[i][1]=1; } f[n][0]=p[n][0];f[n][1]=p[n][1]; for(ll i=n-1;i>=1;i--){ f[i][0]=(f[i+1][0]&p[i][1])|((!f[i+1][0])&p[i][0]); f[i][1]=(f[i+1][1]&p[i][1])|((!f[i+1][1])&p[i][0]); } printf("%lld %lld\n",f[1][0],f[1][1]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16049128.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示