[bzoj4881][Lydsy2017年5月月赛]线段游戏

 2023-09-11 阅读 19 评论 0

摘要:来自FallDream的博客,未经允许,请勿转载,谢谢。 quailty和tangjz正在玩一个关于线段的游戏。在平面上有n条线段,编号依次为1到n。其中第i条线段的两端点坐标分别为(0,i)和(1,p_i),其中p_1,p_2,...,p_n构成了1到n的一个排列。quailty先手&#

来自FallDream的博客,未经允许,请勿转载,谢谢。


quailty和tangjz正在玩一个关于线段的游戏。在平面上有n条线段,编号依次为1到n。其中第i条线段的两端点坐标分别为(0,i)和(1,p_i),其中p_1,p_2,...,p_n构成了1到n的一个排列。quailty先手,他可以选择一些互不相交的线段,将它们拿走,当然他也可以一条线段也不选。然后tangjz必须拿走所有剩下的线段,若有两条线段相交,那么他就输了,否则他就赢了。注意若quailty拿走了全部线段,那么tangjz也会胜利。quailty深深喜欢着tangjz,所以他不希望tangjz输掉游戏,请计算他有多少种选择线段的方式,使得tangjz可以赢得游戏。
n<=100000
这道题挺有意思的233
如果把线段只要有相交的就成一个块,可以得到很多块。答案应该是2^块的个数次方。
特判无解,也就是如果有三条或者更多的线段互相交织,那么显然无解。只需要对每个块做一次,维护当前右端点最大值,和当前最右的那条线段相交的右端点的最大值即可判定。
网上好像有一些看起来比较靠谱的做法 但是我这个扫一遍就行了,复杂度O(n)  
轻松rank1
#include<iostream>
#include<cstdio>
#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:(*S++))
char B[1<<15],*S=B,*T=B;
#define mod 998244353
using namespace std;
inline int read()
{int x = 0; char ch = getchar();while(ch < '0' || ch > '9')  ch = getchar();while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x;
}int ans=0,n,a[100005],pre=0;
bool flag=0;inline int pow(int x,int k)
{int sum=1;for(;k;k>>=1,x=1LL*x*x%mod)if(k&1) sum=1LL*sum*x%mod;return sum;
}inline void Solve(int l,int r)
{int mx=0,Mx=0;for(register int i=l;i<=r&&!flag;++i){if(a[i]<mx&&a[i]<Mx) flag=1;if(a[i]>mx) mx=a[i],Mx=0;else if(a[i]>Mx) Mx=a[i];}
}int main()
{n=read();for(register int i=1,Mx=0;i<=n&&!flag;Mx=max(Mx,a[i++])) if((a[i]=read())==i&&Mx<i) Solve(pre+1,i-1),ans+=1+(pre!=i-1),pre=i;Solve(pre+1,n);if(pre!=n) ++ans;printf("%d\n",flag?0:pow(2,ans));return 0;
}

转载于:https://www.cnblogs.com/FallDream/p/bzoj4881.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/45059.html

下一篇:test23

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息