#树状数组,dp#洛谷 3506 [POI2010]MOT-Monotonicity 2
题目
给出\(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;
}

浙公网安备 33010602011771号