2019.01.26-bzoj2090: [Poi2010]Monotonicity 2
题目描述:
给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。
算法标签:dp,树状数组
思路:
令f[i]为第i位能最多匹配到的选出的子序列的第几位。然后可以由前向后转移,用树状数组维护,小于和大于的情况,等于的用一个数组维护即可。
讲的不清楚,其实看看代码也能很快理解。
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e6+5; char s[5]; int n,k,a[N],b[N],mx,t[2][N],p[N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il void ins(int op,int x,int v){ for(;x<=mx;x+=x&-x)t[op][x]=max(v,t[op][x]); } il int query(int op,int x){ int res=0; for(;x;x-=x&-x)res=max(res,t[op][x]); return res; } int main() { n=read();k=read(); for(int i=1;i<=n;i++)a[i]=read(),mx=max(a[i],mx); for(int i=1;i<=k;i++){ scanf(" %s",s+1); if(s[1]=='<')b[i]=1; else if(s[1]=='=')b[i]=2; else b[i]=3; } int ans=0; for(int i=1;i<=n;i++){ int x=max(p[a[i]],max(query(0,a[i]-1),query(1,mx-a[i]))); int y=x%k+1;ans=max(ans,x+1); if(b[y]==1)ins(0,a[i],x+1); else if(b[y]==2)p[a[i]]=max(p[a[i]],x+1); else ins(1,mx-a[i]+1,x+1); } printf("%d\n",ans); return 0; }