[2018.10.15 T3] 数列

暂无连接

数列

【题目描述】

小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[i1]

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]=0a[p[i]][q[i]]a[p[i1]][q[i1]]

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[i1]][q[i1]],要么都有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[i1]][q[i1]])。

小Q希望这个二元组序列尽可能长。

提示:当q[i]!=q[i−1]q[i]!=q[i-1]q[i]!=q[i1]时,数列的增减性由q[i]q[i]q[i]而非q[i−1]q[i-1]q[i1]决定。

【简版题意】

小Q拿到一个3×n3×n3×n的数组,要在每一列选一个数(或者不选),满足以下条件:

(1)如果在第一行选,那它必须大于等于上一个数

(2)如果在第二行选,那么必须小于等于上一个数

(3)如果在第三行选,对于连续的一段在第三行选的数,必须满足方向相同(都小于等于上一个数或者都大于等于上一个数)

【输入】

输入包含444行,第一行包含一个整数nnn表示数列长度,第2、3、42、3、4234行每行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(增),然后取第111666(增),然后取第三行5 45\ 45 4(减),长度为666

【数据规模和约定】

对于20%20\%20%的数据,n≤10,m≤1000n≤10,m≤1000n10m1000
对于60%60\%60%的数据,n≤1000,m≤1000n≤1000,m≤1000n1000m1000
对于100%100\%100%的数据,n≤100,000,m≤109n≤100,000,m≤10^9n100,000m109

其中m=max∣a[i]∣m=max|a[i]|m=maxa[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(log⁡n)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();}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值