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;
}

 

posted on 2018-06-29 11:38  Narh  阅读(126)  评论(0编辑  收藏  举报

导航