[2018.10.15 T3] 數列

暫無連接

數列

【題目描述】

小Q和小C是好朋友。

小Q喜歡數列。有一天,他心血來潮,寫下了三個長度均爲nn的數列。

小C也很喜歡數列。但是他只喜歡其中一種,波動數列。

小C把他的喜好告訴了小Q。小Q便打算找出這三個數列內的最長波動數列。

也就是說,如果我們將三個數列記做a[n][3]a[n][3],他必須要構造一個二元組序列:(p[i],q[i])(p[i], q[i]),使得對於任何i>1i>1有:

p[i]>p[i1]p[i]>p[i-1]

q[i]=0a[p[i]][q[i]]a[p[i1]][q[i1]]q[i]=0,a[p[i]][q[i]]≥a[p[i-1]][q[i-1]]

q[i]=2q[i]=2,只要保持段內同向即可(就是對於連續的一段q[i]=2q[i]=2,要麼都有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[i1]][q[i1]]a[p[i]][q[i]]≤a[p[i-1]][q[i-1]])。

小Q希望這個二元組序列儘可能長。

提示:當q[i]!=q[i1]q[i]!=q[i-1]時,數列的增減性由q[i]q[i]而非q[i1]q[i-1]決定。

【簡版題意】

小Q拿到一個3×n3×n的數組,要在每一列選一個數(或者不選),滿足以下條件:

(1)如果在第一行選,那它必須大於等於上一個數

(2)如果在第二行選,那麼必須小於等於上一個數

(3)如果在第三行選,對於連續的一段在第三行選的數,必須滿足方向相同(都小於等於上一個數或者都大於等於上一個數)

【輸入】

輸入包含44行,第一行包含一個整數nn表示數列長度,第2342、3、4行每行nn個整數,分別表示三個數列。

【輸出】

輸出僅包含一個整數,即最長波動數列的長度。

【輸入樣例】

6
1 2 3 6 5 4
5 4 3 7 8 9
1 2 3 6 5 4

【輸出樣例】

6

【提示】
【樣例解釋】

取第三行1 2 31\ 2\ 3(增),然後取第1166(增),然後取第三行5 45\ 4(減),長度爲66

【數據規模和約定】

對於20%20\%的數據,n10m1000n≤10,m≤1000
對於60%60\%的數據,n1000m1000n≤1000,m≤1000
對於100%100\%的數據,n100,000m109n≤100,000,m≤10^9

其中m=maxa[i]m=max|a[i]|

題解

這道題的題面是真的有毒,完整題面沒說q[i]=1q[i]=1的情況,簡版題面又沒說選選連續第三行的時候增減性要考慮第一個第三行前面的數。。。

讀懂題面以後這道題就變得簡單起來,dp[i][1]dp[i][1]表示選第ii列第一行爲結尾的最長長度,dp[i][2]dp[i][2]同理,dp[i][3]dp[i][3]表示選第三行並且單增,dp[i][4]dp[i][4]表示單減。暴力轉移是O(n2)O(n^2)的,發現轉移時查詢的實際上是值域最大值,所以開一棵值域線段樹即可O(logn)O(\log n)轉移。

代碼
#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();}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章