题目背景
小强和阿米巴是好朋友。
题目描述
小强喜欢数列。有一天,他心血来潮,写下了三个长度均为n的数列。
阿米巴也很喜欢数列。但是他只喜欢其中一种,波动数列。
阿米巴把他的喜好告诉了小强。小强便打算找出这三个数列内的最长波动数列。
也就是说,如果我们将三个数列记做a[n][3],他必须要构造一个二元组序列:<p[i], q[i]>,使得对于任何 i>1 有:
p[i] > p[i-1]
若q[i] = 0,a[p[i]][q[i]] >= a[p[i-1]][q[i-1]]
若q[i] = 1,a[p[i]][q[i]] <= a[p[i-1]][q[i-1]]
若q[i] = 2,只要保持段内同向即可(就是对于连续的一段q[i]=2,要么都有a[p[i]][q[i]] >= a[p[i-1]][q[i-1]],要么都有a[p[i]][q[i]] <= a[p[i-1]][q[i-1]])。
小强希望这个二元组序列尽可能长。
提示:当q[i] != q[i-1]时,数列的增减性由q[i]而非q[i-1]决定。
清晰版题目描述
小强拿到一个3×n的数组,要在每一列选一个数(或者不选),满足以下条件:
1.如果在第一行选,那它必须大于等于上一个数
2.如果在第二行选,那么必须小于等于上一个数
3.如果在第三行选,对于连续的一段在第三行选的数,必须满足方向相同(都小于等于上一个数或者都大于等于上一个数)
输入输出格式
输入格式:
输入包含4行。
第一行一个数n,表示数列长度。
第2、3、4行,每行n个整数,分别表示三个数列。
输出格式:
输出仅包含一个整数,即最长波动数列的长度。
输入输出样例
6
1 2 3 6 5 4
5 4 3 7 8 9
1 2 3 6 5 4
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]表示第i位,选第1行
f[i][2]表示选第2行
f[i][3/4]表示第i位,选第3行,比上一个大/小
满足条件下:
f[i][1]=max(f[j][1~4])
f[i][2]=max(f[j][1~4])
f[i][3]=max(f[j][1,2,3])
f[i][4]=max(f[j][1,2,4])
这样时间复杂度为n^2
用线段树优化至nlogn
把所有a值离散,对应于4颗线段树
转移就变成了区间查询最大值,单点修改
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int c[][],n,sz,a[][],b[],num;
int f[][],s1,s2,s3,s4,ans;
void pushup(int rt,int p)
{
c[rt][p]=max(c[rt*][p],c[rt*+][p]);
}
int query(int rt,int l,int r,int L,int R,int p)
{
if (l>=L&&r<=R)
{
return c[rt][p];
}
int mid=(l+r)/,s=;
if (L<=mid) s=max(s,query(rt*,l,mid,L,R,p));
if (R>mid) s=max(s,query(rt*+,mid+,r,L,R,p));
return s;
}
void update(int rt,int l,int r,int x,int d,int p)
{
if (l==r)
{
c[rt][p]=d;
return;
}
int mid=(l+r)/;
if (x<=mid) update(rt*,l,mid,x,d,p);
else update(rt*+,mid+,r,x,d,p);
pushup(rt,p);
}
int main()
{
int i,j;
cin>>n;
for (j=; j<=; j++)
{
for (i=; i<=n; i++)
{
scanf("%d",&a[i][j]);
num++;
b[num]=a[i][j];
}
}
sort(b+,b+num+);
sz=unique(b+,b+num+)-(b+);
for (j=; j<=; j++)
{
for (i=; i<=n; i++)
a[i][j]=lower_bound(b+,b+sz+,a[i][j])-b;
}
for (i=; i<=n; i++)
a[i][]=a[i][];
for (i=; i<=n; i++)
{
s1=query(,,sz,,a[i][],);
s2=query(,,sz,,a[i][],);
s3=query(,,sz,,a[i][],);
s4=query(,,sz,,a[i][],);
f[i][]=max(f[i][],+max(s1,max(s2,max(s3,s4)))); s1=query(,,sz,a[i][],sz,);
s2=query(,,sz,a[i][],sz,);
s3=query(,,sz,a[i][],sz,);
s4=query(,,sz,a[i][],sz,);
f[i][]=max(f[i][],+max(s1,max(s2,max(s3,s4)))); s1=query(,,sz,,a[i][],);
s2=query(,,sz,,a[i][],);
s3=query(,,sz,,a[i][],);
f[i][]=max(f[i][],+max(s1,max(s2,s3))); s1=query(,,sz,a[i][],sz,);
s2=query(,,sz,a[i][],sz,);
s4=query(,,sz,a[i][],sz,);
f[i][]=max(f[i][],+max(s1,max(s2,s4))); update(,,sz,a[i][],f[i][],);
update(,,sz,a[i][],f[i][],);
update(,,sz,a[i][],f[i][],);
update(,,sz,a[i][],f[i][],);
ans=max(ans,max(f[i][],max(f[i][],max(f[i][],f[i][]))));
}
cout<<ans;
}