题目
给出(N)个正整数(a[1..N]),再给出(K)个关系符号(>、<或=)(s[1..k])。
选出一个长度为(L)的子序列(不要求连续),要求这个子序列的第(i)项和第(i+1)项的的大小关系为(s[(i-1)mod K+1])。
求出(L)的最大值。并输出一组具体方案。
分析
设(dp[i])表示以(i)结尾的(L)的最大值,
则(dp[i]=max{dp[j]+1})
可以发现偏序关系实则是由(dp[j])来决定的,
而且更小的(dp[j])不能够影响(i)以后的选择
对于小于号和大于号开两个树状数组记录最大的(dp[j]),
等于号就直接记录上一次出现的位置即可
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=500011; char p[N];
int dp[N],n,m,k,b[N],a[N],pre[N],ans,pos[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void dfs(int n){
if (!n) return;
dfs(pre[n]);
print(b[a[n]]),putchar(32);
}
struct Tree_Array{
int c[N];
inline void update(int x,int y){
for (;x<=k;x+=-x&x)
if (dp[c[x]]<dp[y])
c[x]=y;
}
inline signed query(int x){
rr int ans=0;
for (;x;x-=-x&x)
if (dp[ans]<dp[c[x]])
ans=c[x];
return ans;
}
}c0,c1;
signed main(){
n=iut(); m=iut();
for (rr int i=1;i<=n;++i) b[i]=a[i]=iut(),dp[i]=1;
sort(b+1,b+1+n),k=unique(b+1,b+1+n)-b-1;
for (rr int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+k,a[i])-b;
for (rr int i=1;i<=m;++i){
rr char ch=getchar();
while (ch!='<'&&ch!='>'&&ch!='=') ch=getchar();
for (rr int j=i;j<=n;j+=m) p[j]=ch;
}
for (rr int i=1,j;i<=n;++i){
if (dp[i]<dp[j=c0.query(a[i]-1)]+1) dp[i]=dp[j]+1,pre[i]=j;
if (dp[i]<dp[j=c1.query(k-a[i])]+1) dp[i]=dp[j]+1,pre[i]=j;
if (dp[i]<dp[j=pos[a[i]]]+1) dp[i]=dp[j]+1,pre[i]=j;
if (p[dp[i]]=='<') c0.update(a[i],i);
if (p[dp[i]]=='>') c1.update(k-a[i]+1,i);
if (p[dp[i]]=='=') pos[a[i]]=i;
if (dp[ans]<dp[i]) ans=i;
}
print(dp[ans]),putchar(10),dfs(ans);
return 0;
}