bzoj 2089/2090: [Poi2010]Monotonicity 2 — 线段树优化dp
Contents
2090: [Poi2010]Monotonicity 2
Time Limit: 30 Sec Memory Limit: 259 MB
Description
给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。
Input
第一行两个正整数,分别表示N和K (N, K <= 500,000)。
第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6)。
第三行给出K个空格隔开关系符号(>、<或=),第i个表示s[i]。
Output
一个正整数,表示L的最大值。
Sample Input
7 3
2 4 3 1 3 5 3
< > =
2 4 3 1 3 5 3
< > =
Sample Output
6
HINT
选出的子序列为2 4 3 3 5 3,相邻大小关系分别是< > = < >。
Source
很好玩的方式
首先,我们考虑dp,用f[i]表示到第i位时的最长长度
所以这个时候他连接下一位的符号是固定的
这样我们就可以分三类:
如果是=,就开一个桶记录一下值为这个是的当前最优解
如果是<,我们可以推入一个下一位是小于号的线段树,以权值为下表,维护f值
然后下次更新f的时候,取出合法区间的最大的值就好了
如果是>,同理可以维护一个下一位是小于号的线段树
这样就可以做到时间复杂度O(nlogn)了
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1000000007
#define ll long long
#define N 1000010
inline int rd()
{
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;
}
int n,k,nn,a[N],op[N],f[N],ans;
struct segtr
{
#define ls p<<1
#define rs p<<1|1
int mx[N<<2];
void xg(int p,int l,int r,int x,int v)
{
if(l==r){mx[p]=v;return;}
int mid=l+r>>1;
x<=mid?xg(ls,l,mid,x,v):xg(rs,mid+1,r,x,v);
mx[p]=max(mx[ls],mx[rs]);
}
int fd(int p,int l,int r,int L,int R)
{
if(L>R) return 0;
if(l==L&&R==r) return mx[p];
int mid=l+r>>1;
if(R<=mid) return fd(ls,l,mid,L,R);
if(L>mid) return fd(rs,mid+1,r,L,R);
return max(fd(ls,l,mid,L,mid),fd(rs,mid+1,r,mid+1,R));
}
}tr[2];
int ji[N];
int main()
{
n=rd();k=rd();
for(int i=1;i<=n;i++) a[i]=rd(),nn=max(a[i],nn);
char ch[5];
for(int i=1;i<=k;i++)
{
scanf("%s",ch);
if(ch[0]=='>') op[i]=0;
else if(ch[0]=='<') op[i]=1;
else op[i]=2;
}
for(int i=1,tt;i<=n;i++)
{
tt=max(tr[0].fd(1,1,nn,a[i]+1,nn),tr[1].fd(1,1,nn,1,a[i]-1));
f[i]=max(tt,ji[a[i]])+1;
ans=max(ans,f[i]);
tt=op[(f[i]-1)%k+1];
if(tt==2) ji[a[i]]=max(f[i],ji[a[i]]);
else tr[tt].xg(1,1,nn,a[i],f[i]);
}
printf("%d\n",ans);
return 0;
}
发表评论