bzoj 4881 [Lydsy1705月赛]线段游戏
Posted narh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4881 [Lydsy1705月赛]线段游戏相关的知识,希望对你有一定的参考价值。
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4881
1.当一块相互交织的线段中有3个或以上两两相交的那种线段时,无解。
这就是最长下降子序列!(不是某条线段的逆序对!)判断一下最长下降子序列长度是否>2。
正着 n-a[i]+1 (不是 n-i+1 !)或倒着 a[i] 。
2.只要数有几个块,答案就是2^(块数)。
数块方法:用set。一块只留下它最靠右的那条(用来和别人相交)。新入一条线段要把它到最右边的线段们只留下最右边的。
#include<iostream> #include<cstdio> #include<cstring> #include<set> #define ll long long using namespace std; const int N=1e5+5; const ll mod=998244353; int n,a[N],f[N]; set<int> st; bool flag; int rdn() { int ret=0,fx=1;char ch=getchar(); while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)fx=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘)(ret*=10)+=ch-‘0‘,ch=getchar(); return ret*fx; } ll pw(int k) { ll ret=1; while(k--)(ret<<=1)%=mod; return ret; } int query(int x) { int ret=0;for(;x;x-=(x&-x))ret=max(ret,f[x]);return ret; } void add(int v,int x) { for(;x<=n;x+=(x&-x))f[x]=max(f[x],v); } void solve() { for(int i=n;i;i--) { int k=query(a[i])+1; if(k>2){flag=1;return;} add(k,a[i]); } } int main() { n=rdn();for(int i=1;i<=n;i++)a[i]=rdn(); solve(); if(flag){printf("0");return 0;} for(int i=1;i<=n;i++) { set<int>::iterator k=st.upper_bound(a[i]); if(k!=st.end()) { int r=*k; set<int>::iterator v=st.end(); v--;int u=*v; while(1) { set<int>::iterator it=st.end(); it--;int s=*it; st.erase(it); if(s==r)break; } st.insert(u); } else st.insert(a[i]); } printf("%lld",pw(st.size())); return 0; }
以上是关于bzoj 4881 [Lydsy1705月赛]线段游戏的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶