暂无连接
数列
【题目描述】
小Q和小C是好朋友。
小Q喜欢数列。有一天,他心血来潮,写下了三个长度均为nnn的数列。
小C也很喜欢数列。但是他只喜欢其中一种,波动数列。
小C把他的喜好告诉了小Q。小Q便打算找出这三个数列内的最长波动数列。
也就是说,如果我们将三个数列记做a[n][3]a[n][3]a[n][3],他必须要构造一个二元组序列:(p[i],q[i])(p[i], q[i])(p[i],q[i]),使得对于任何i>1i>1i>1有:
p[i]>p[i−1]p[i]>p[i-1]p[i]>p[i−1]
若q[i]=0,a[p[i]][q[i]]≥a[p[i−1]][q[i−1]]q[i]=0,a[p[i]][q[i]]≥a[p[i-1]][q[i-1]]q[i]=0,a[p[i]][q[i]]≥a[p[i−1]][q[i−1]]
若q[i]=2q[i]=2q[i]=2,只要保持段内同向即可(就是对于连续的一段q[i]=2q[i]=2q[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]]a[p[i]][q[i]]≥a[p[i−1]][q[i−1]],要么都有a[p[i]][q[i]]≤a[p[i−1]][q[i−1]]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希望这个二元组序列尽可能长。
提示:当q[i]!=q[i−1]q[i]!=q[i-1]q[i]!=q[i−1]时,数列的增减性由q[i]q[i]q[i]而非q[i−1]q[i-1]q[i−1]决定。
【简版题意】
小Q拿到一个3×n3×n3×n的数组,要在每一列选一个数(或者不选),满足以下条件:
(1)如果在第一行选,那它必须大于等于上一个数
(2)如果在第二行选,那么必须小于等于上一个数
(3)如果在第三行选,对于连续的一段在第三行选的数,必须满足方向相同(都小于等于上一个数或者都大于等于上一个数)
【输入】
输入包含444行,第一行包含一个整数nnn表示数列长度,第2、3、42、3、42、3、4行每行nnn个整数,分别表示三个数列。
【输出】
输出仅包含一个整数,即最长波动数列的长度。
【输入样例】
6
1 2 3 6 5 4
5 4 3 7 8 9
1 2 3 6 5 4
【输出样例】
6
【提示】
【样例解释】
取第三行1 2 31\ 2\ 31 2 3(增),然后取第111行666(增),然后取第三行5 45\ 45 4(减),长度为666。
【数据规模和约定】
对于20%20\%20%的数据,n≤10,m≤1000n≤10,m≤1000n≤10,m≤1000;
对于60%60\%60%的数据,n≤1000,m≤1000n≤1000,m≤1000n≤1000,m≤1000;
对于100%100\%100%的数据,n≤100,000,m≤109n≤100,000,m≤10^9n≤100,000,m≤109;
其中m=max∣a[i]∣m=max|a[i]|m=max∣a[i]∣。
题解
这道题的题面是真的有毒,完整题面没说q[i]=1q[i]=1q[i]=1的情况,简版题面又没说选选连续第三行的时候增减性要考虑第一个第三行前面的数。。。
读懂题面以后这道题就变得简单起来,dp[i][1]dp[i][1]dp[i][1]表示选第iii列第一行为结尾的最长长度,dp[i][2]dp[i][2]dp[i][2]同理,dp[i][3]dp[i][3]dp[i][3]表示选第三行并且单增,dp[i][4]dp[i][4]dp[i][4]表示单减。暴力转移是O(n2)O(n^2)O(n2)的,发现转移时查询的实际上是值域最大值,所以开一棵值域线段树即可O(logn)O(\log n)O(logn)转移。
代码
#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
int dp[M][5],a[M][5],data[M<<2],n,ans,q;
struct sd{
int mx[M<<4];
void up(int v){mx[v]=max(mx[ls],mx[rs]);}
void add(int v,int le,int ri,int pos,int val)
{
if(le==ri){mx[v]=max(mx[v],val);return;}
int mid=le+ri>>1;
if(pos<=mid)add(ls,le,mid,pos,val);
else add(rs,mid+1,ri,pos,val);
up(v);
}
int ask(int v,int le,int ri,int lb,int rb)
{
if(lb<=le&&ri<=rb){return mx[v];}
int mid=le+ri>>1,ans=0;
if(lb<=mid)ans=ask(ls,le,mid,lb,rb);
if(mid<rb)ans=max(ans,ask(rs,mid+1,ri,lb,rb));
return ans;
}
}sgt[4];
void in()
{
scanf("%d",&n);
for(int j=1;j<=3;++j)for(int i=1;i<=n;++i)scanf("%d",&a[i][j]),data[++q]=a[i][j];
data[++q]=INT_MAX;
}
void ac()
{
sort(data+1,data+1+q);q=unique(data+1,data+1+q)-data-1;
for(int j=1;j<=3;++j)for(int i=1;i<=n;++i)a[i][j]=lower_bound(data+1,data+1+q,a[i][j])-data;
for(int i=1;i<=n;++i)
{
dp[i][1]=max(max(sgt[1].ask(1,1,q,1,a[i][1]),sgt[2].ask(1,1,q,1,a[i][1])),sgt[3].ask(1,1,q,1,a[i][1]))+1;
dp[i][2]=max(max(sgt[1].ask(1,1,q,a[i][2],q),sgt[2].ask(1,1,q,a[i][2],q)),sgt[3].ask(1,1,q,a[i][2],q))+1;
dp[i][3]=max(sgt[1].ask(1,1,q,1,a[i][3]),sgt[2].ask(1,1,q,1,a[i][3]))+1;
dp[i][4]=max(sgt[1].ask(1,1,q,a[i][3],q),sgt[3].ask(1,1,q,a[i][3],q))+1;
sgt[1].add(1,1,q,a[i][1],dp[i][1]),sgt[1].add(1,1,q,a[i][2],dp[i][2]),
sgt[2].add(1,1,q,a[i][3],dp[i][3]),sgt[3].add(1,1,q,a[i][3],dp[i][4]);
}
for(int i=1;i<=n;++i)for(int j=1;j<=4;++j)ans=max(ans,dp[i][j]);
printf("%d",ans);
}
int main(){in(),ac();}