P3928 SAC E#1 - 一道简单题 Sequence2
Posted Z-Y-Y-S
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3928 SAC E#1 - 一道简单题 Sequence2相关的知识,希望对你有一定的参考价值。
题目背景
小强和阿米巴是好朋友。
题目描述
小强喜欢数列。有一天,他心血来潮,写下了三个长度均为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颗线段树
转移就变成了区间查询最大值,单点修改
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int c[3200001][5],n,sz,a[200001][5],b[1000001],num; 7 int f[200001][5],s1,s2,s3,s4,ans; 8 void pushup(int rt,int p) 9 { 10 c[rt][p]=max(c[rt*2][p],c[rt*2+1][p]); 11 } 12 int query(int rt,int l,int r,int L,int R,int p) 13 { 14 if (l>=L&&r<=R) 15 { 16 return c[rt][p]; 17 } 18 int mid=(l+r)/2,s=0; 19 if (L<=mid) s=max(s,query(rt*2,l,mid,L,R,p)); 20 if (R>mid) s=max(s,query(rt*2+1,mid+1,r,L,R,p)); 21 return s; 22 } 23 void update(int rt,int l,int r,int x,int d,int p) 24 { 25 if (l==r) 26 { 27 c[rt][p]=d; 28 return; 29 } 30 int mid=(l+r)/2; 31 if (x<=mid) update(rt*2,l,mid,x,d,p); 32 else update(rt*2+1,mid+1,r,x,d,p); 33 pushup(rt,p); 34 } 35 int main() 36 { 37 int i,j; 38 cin>>n; 39 for (j=1; j<=3; j++) 40 { 41 for (i=1; i<=n; i++) 42 { 43 scanf("%d",&a[i][j]); 44 num++; 45 b[num]=a[i][j]; 46 } 47 } 48 sort(b+1,b+num+1); 49 sz=unique(b+1,b+num+1)-(b+1); 50 for (j=1; j<=3; j++) 51 { 52 for (i=1; i<=n; i++) 53 a[i][j]=lower_bound(b+1,b+sz+1,a[i][j])-b; 54 } 55 for (i=1; i<=n; i++) 56 a[i][4]=a[i][3]; 57 for (i=1; i<=n; i++) 58 { 59 s1=query(1,1,sz,1,a[i][1],1); 60 s2=query(1,1,sz,1,a[i][1],2); 61 s3=query(1,1,sz,1,a[i][1],3); 62 s4=query(1,1,sz,1,a[i][1],4); 63 f[i][1]=max(f[i][1],1+max(s1,max(s2,max(s3,s4)))); 64 65 s1=query(1,1,sz,a[i][2],sz,1); 66 s2=query(1,1,sz,a[i][2],sz,2); 67 s3=query(1,1,sz,a[i][2],sz,3); 68 s4=query(1,1,sz,a[i][2],sz,4); 69 f[i][2]=max(f[i][2],1+max(s1,max(s2,max(s3,s4)))); 70 71 s1=query(1,1,sz,1,a[i][3],1); 72 s2=query(1,1,sz,1,a[i][3],2); 73 s3=query(1,1,sz,1,a[i][3],3); 74 f[i][3]=max(f[i][3],1+max(s1,max(s2,s3))); 75 76 s1=query(1,1,sz,a[i][4],sz,1); 77 s2=query(1,1,sz,a[i][4],sz,2); 78 s4=query(1,1,sz,a[i][4],sz,4); 79 f[i][4]=max(f[i][4],1+max(s1,max(s2,s4))); 80 81 update(1,1,sz,a[i][1],f[i][1],1); 82 update(1,1,sz,a[i][2],f[i][2],2); 83 update(1,1,sz,a[i][3],f[i][3],3); 84 update(1,1,sz,a[i][4],f[i][4],4); 85 ans=max(ans,max(f[i][1],max(f[i][2],max(f[i][3],f[i][4])))); 86 } 87 cout<<ans; 88 }
以上是关于P3928 SAC E#1 - 一道简单题 Sequence2的主要内容,如果未能解决你的问题,请参考以下文章
P3928 SAC E#1 - 一道简单题 Sequence2
洛谷P3928 SAC E#1 - 一道简单题 Sequence2
洛谷P3928SAC E#1 - 一道简单题 Sequence2