标签:DP,线段树,数据结构
清晰版题目描述
小强拿到一个3×n的数组,要在每一列选一个数(或者不选),满足以下条件:
1.如果在第一行选,那它必须大于等于上一个数
2.如果在第二行选,那么必须小于等于上一个数
3.如果在第三行选,对于连续的一段在第三行选的数,必须满足方向相同(都小于等于上一个数或者都大于等于上一个数)
输入输出格式
输入格式:
输入包含4行。
第一行一个数n,表示数列长度。
第2、3、4行,每行n个整数,分别表示三个数列。
输出格式:
输出仅包含一个整数,即最长波动数列的长度。
输入输出样例
输入样例#1: 复制
6
1 2 3 6 5 4
5 4 3 7 8 9
1 2 3 6 5 4
输出样例#1: 复制
6
说明
对于20%的数据,n <= 10, m <= 1000
对于60%的数据,n <=1000, m <= 1000
对于100%的数据, n <=100000, m <= 1000000000
其中m = max|a[i]|
样例解释:
取第三行1 2 3(增),然后取第1行6(增),然后取第三行5 4(减),长度为6。
分析:DP裸题,设f[i][1/2/3/4]分别表示取前i列数中以第1/2/3/4行结尾的最长波动数列长度
F[i][1]=max(f[j][1/2/3/4]+1) j<i 且a[j][1/2/3/4]<=a[i][1]
剩下三行的转移同理,这种做法时间复杂度为O(n^2)
满分的做法可以直接用线段树维护
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define mem(x,num) memset(x,num,sizeof x)
#define LL long long
using namespace std;
inline LL read()
{
LL f=1,x=0;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;
}
const int maxn=1e5+6;
int n,cnt=0,ans=0;
int a[maxn],b[maxn],c[maxn],num[maxn<<4],f[maxn][5],tree[maxn<<4][5];
void insert(int id,int rt,int l,int r,int pos,int v){
if(l==r){tree[rt][id]=max(tree[rt][id],v);return;}
int mid=(l+r)>>1;
if(pos<=mid)insert(id,rt<<1,l,mid,pos,v);
else insert(id,rt<<1|1,mid+1,r,pos,v);
tree[rt][id]=max(tree[rt<<1][id],tree[rt<<1|1][id]);
}
int query(int id,int rt,int l,int r,int L,int R){
if(L<=l&&r<=R)return tree[rt][id];
int mid=(l+r)>>1,ans=0;
if(L<=mid)ans=max(ans,query(id,rt<<1,l,mid,L,R));
if(mid+1<=R)ans=max(ans,query(id,rt<<1|1,mid+1,r,L,R));
return ans;
}
int main()
{
n=read();
rep(i,1,n)a[i]=read(),num[++cnt]=a[i];
rep(i,1,n)b[i]=read(),num[++cnt]=b[i];
rep(i,1,n)c[i]=read(),num[++cnt]=c[i];
sort(num+1,num+1+cnt);
cnt=unique(num+1,num+cnt+1)-num-1;
rep(i,1,n)a[i]=lower_bound(num+1,num+cnt+1,a[i])-num;
rep(i,1,n)b[i]=lower_bound(num+1,num+cnt+1,b[i])-num;
rep(i,1,n)c[i]=lower_bound(num+1,num+cnt+1,c[i])-num;
rep(i,1,n){
f[i][1]=max(f[i][1],query(1,1,1,cnt,1,a[i]));
f[i][1]=max(f[i][1],query(2,1,1,cnt,1,a[i]));
f[i][1]=max(f[i][1],query(3,1,1,cnt,1,a[i]));
f[i][1]=max(f[i][1],query(4,1,1,cnt,1,a[i]));
f[i][1]++;
f[i][2]=max(f[i][2],query(1,1,1,cnt,b[i],cnt));
f[i][2]=max(f[i][2],query(2,1,1,cnt,b[i],cnt));
f[i][2]=max(f[i][2],query(3,1,1,cnt,b[i],cnt));
f[i][2]=max(f[i][2],query(4,1,1,cnt,b[i],cnt));
f[i][2]++;
f[i][3]=max(f[i][3],query(1,1,1,cnt,1,c[i]));
f[i][3]=max(f[i][3],query(2,1,1,cnt,1,c[i]));
f[i][3]=max(f[i][3],query(3,1,1,cnt,1,c[i]));
f[i][3]++;
f[i][4]=max(f[i][4],query(1,1,1,cnt,c[i],cnt));
f[i][4]=max(f[i][4],query(2,1,1,cnt,c[i],cnt));
f[i][4]=max(f[i][4],query(4,1,1,cnt,c[i],cnt));
f[i][4]++;
insert(1,1,1,cnt,a[i],f[i][1]);
insert(2,1,1,cnt,b[i],f[i][2]);
insert(3,1,1,cnt,c[i],f[i][3]);
insert(4,1,1,cnt,c[i],f[i][4]);
}
rep(i,1,n)
rep(j,1,4)ans=max(ans,f[i][j]);
printf("%d\n",ans);
return 0;
}