BZOJ2090 [POI2010]MOT-Monotonicity 2

Description

给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。

  如果没有s数组的限制,这道题就是一道简单的打导弹,所以我们任然考虑DP。我们考虑证明决策单调性。

  考虑一个序列的末尾q与一个新的数p,下面证明p代替q,答案不会更优秀。

  考虑s序列<><,即q<p,若p代替q,答案会更优,则有数z,t,满足p<z>t。但是注意q<p,所以一定有q<z>t。故答案不会更优。

  那么线段树优化DP即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
int read(){
    int x=0,f=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Ans{
    int a,pre;
};
struct Tre{
    int a[N*4+5],pre[N*4+5];
    void insert(int p,int l,int r,int x,int v,int o){
        if (l==r){pre[p]=o; a[p]=v; return;}
        int mid=(l+r)>>1;
        if (x<=mid) insert(p*2,l,mid,x,v,o);
        else insert(p*2+1,mid+1,r,x,v,o);
        int ls=p*2; int rs=ls+1;
        if (a[ls]>=a[rs]) {a[p]=a[ls]; pre[p]=pre[ls];}
        else{a[p]=a[rs]; pre[p]=pre[rs];}
    }
    Ans query(int p,int l,int r,int ql,int qr){
        Ans q; q.a=0; q.pre=0;
        if (qr<ql) return q;
        if (ql<=l&&qr>=r){ Ans b; b.a=a[p]; b.pre=pre[p]; return b;}
        int mid=(l+r)>>1;
        if (ql<=mid) {Ans b=query(p*2,l,mid,ql,qr); if (b.a>q.a) q=b;}
        if (qr>mid){Ans b=query(p*2+1,mid+1,r,ql,qr); if (b.a>q.a) q=b;}
        return q;
    }
}T1,T2;
int a[N],s[N],f[N],fr[N],qs[N*2],qsf[N*2],sol[N];
void Pri(int x){
    if (x==0) return;
    sol[++sol[0]]=x;
    x=fr[x];
    Pri(x);
}
int main(){
    int mx=0,mn=1000000,n=read(),k=read();
    for (int i=1;i<=n;i++) {
    a[i]=read(); if (a[i]>mx) mx=a[i];}
    char c[N];
    for (int i=1;i<=k;i++){
        cin>>c;
        if (c[0]=='<') s[i]=0;
        if (c[0]=='>') s[i]=1;
        if (c[0]=='=') s[i]=2;
    }
    for (int i=1;i<=n;i++){
        f[i]=qs[a[i]]+1; fr[i]=qsf[a[i]];
        Ans a1=T1.query(1,1,mx,1,a[i]-1);
        Ans a2=T2.query(1,1,mx,a[i]+1,mx);
        Ans c;
        if (a1.a>a2.a) c=a1; else c=a2; 
        if (c.a+1>f[i]) f[i]=c.a+1,fr[i]=c.pre; 
        int fh=s[(f[i]-1)%k+1];
        if (fh==2) qs[a[i]]=f[i],qsf[a[i]]=i;
        if (fh==0) T1.insert(1,1,mx,a[i],f[i],i);
        if (fh==1) T2.insert(1,1,mx,a[i],f[i],i);
    }
    Ans ans; ans.a=0;
    for (int i=1;i<=n;i++) if (f[i]>ans.a) ans.a=f[i],ans.pre=i;
    Pri(ans.pre);
    printf("%d\n",ans.a);
    for (int i=ans.a;i>=1;i--){
        printf("%d ",a[sol[i]]);
    }
    printf("\n");
    return 0;
}
View Code

 

posted @ 2020-10-16 15:06  Cardinal  阅读(108)  评论(0)    收藏  举报