P3928 SAC E#1 - 一道简单题 Sequence2
2017-10-07 18:29
288 查看
题目背景
小强和阿米巴是好朋友。题目描述
小强喜欢数列。有一天,他心血来潮,写下了三个长度均为n的数列。阿米巴也很喜欢数列。但是他只喜欢其中一种,波动数列。
阿米巴把他的喜好告诉了小强。小强便打算找出这三个数列内的最长波动数列。
也就是说,如果我们将三个数列记做a
[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个整数,分别表示三个数列。
输出格式:
输出仅包含一个整数,即最长波动数列的长度。
输入输出样例
输入样例#1:6 1 2 3 6 5 4 5 4 3 7 8 9 1 2 3 6 5 4
输出样例#1:
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。
[b]我们考虑dp[/b]
[b]f[i][1]表示第i位,选第1行[/b]
[b]f[i][2]表示选第2行[/b]
[b]f[i][3/4]表示第i位,选第3行,比上一个大/小[/b]
[b]满足条件下:[/b]
[b]f[i][1]=max(f[j][1~4])[/b]
[b]f[i][2]=max(f[j][1~4])[/b]
[b]f[i][3]=max(f[j][1,2,3])[/b]
[b]f[i][4]=max(f[j][1,2,4])[/b]
[b]这样时间复杂度为n^2[/b]
[b]用线段树优化至nlogn[/b]
[b]把所有a值离散,对应于4颗线段树[/b]
[b]转移就变成了区间查询最大值,单点修改[/b]
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int c[3200001][5],n,sz,a[200001][5],b[1000001],num; int f[200001][5],s1,s2,s3,s4,ans; void pushup(int rt,int p) { c[rt][p]=max(c[rt*2][p],c[rt*2+1][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)/2,s=0; if (L<=mid) s=max(s,query(rt*2,l,mid,L,R,p)); if (R>mid) s=max(s,query(rt*2+1,mid+1,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)/2; if (x<=mid) update(rt*2,l,mid,x,d,p); else update(rt*2+1,mid+1,r,x,d,p); pushup(rt,p); } int main() { int i,j; cin>>n; for (j=1; j<=3; j++) { for (i=1; i<=n; i++) { scanf("%d",&a[i][j]); num++; b[num]=a[i][j]; } } sort(b+1,b+num+1); sz=unique(b+1,b+num+1)-(b+1); for (j=1; j<=3; j++) { for (i=1; i<=n; i++) a[i][j]=lower_bound(b+1,b+sz+1,a[i][j])-b; } for (i=1; i<=n; i++) a[i][4]=a[i][3]; for (i=1; i<=n; i++) { s1=query(1,1,sz,1,a[i][1],1); s2=query(1,1,sz,1,a[i][1],2); s3=query(1,1,sz,1,a[i][1],3); s4=query(1,1,sz,1,a[i][1],4); f[i][1]=max(f[i][1],1+max(s1,max(s2,max(s3,s4)))); s1=query(1,1,sz,a[i][2],sz,1); s2=query(1,1,sz,a[i][2],sz,2); s3=query(1,1,sz,a[i][2],sz,3); s4=query(1,1,sz,a[i][2],sz,4); f[i][2]=max(f[i][2],1+max(s1,max(s2,max(s3,s4)))); s1=query(1,1,sz,1,a[i][3],1); s2=query(1,1,sz,1,a[i][3],2); s3=query(1,1,sz,1,a[i][3],3); f[i][3]=max(f[i][3],1+max(s1,max(s2,s3))); s1=query(1,1,sz,a[i][4],sz,1); s2=query(1,1,sz,a[i][4],sz,2); s4=query(1,1,sz,a[i][4],sz,4); f[i][4]=max(f[i][4],1+max(s1,max(s2,s4))); update(1,1,sz,a[i][1],f[i][1],1); update(1,1,sz,a[i][2],f[i][2],2); update(1,1,sz,a[i][3],f[i][3],3); update(1,1,sz,a[i][4],f[i][4],4); ans=max(ans,max(f[i][1],max(f[i][2],max(f[i][3],f[i][4])))); } cout<<ans; }
相关文章推荐
- 【Luogu】 P3928 SAC E#1 - 一道简单题 Sequence2
- 洛谷10月月赛R1·浴谷八连测R1·提高组 SAC E#1 - T2一道简单题 Sequence2
- 洛谷10月月赛R1·浴谷八连测R1·提高组:SAC E#1 - 一道简单题 Sequence2
- SAC E#1 - 一道神题 Sequence1
- POJ1142Smith Numbers一道简单的数学题
- 简单理解一道关于#ifndef 和extern "C"的题
- 一道简单的C++题目
- cocos2d-x 一道简单面试题,触摸事件的重新分发
- 一道简单的递归题
- 一道简单的ACM题目讨论
- 一道看似复杂但是简单的c#面试题
- qduoj kkun的一道简单签到题(优先队列)
- 【一天一道LeetCode】#60. Permutation Sequence.
- 一道简单笔试题
- hdu 5805 NanoApe Loves Sequence(简单思路题)
- 一道简单的面试题目:输入1234输出1_2_3_4
- 一道简单的题目引发的思考
- sony招聘中的一道简单的C程序填空题
- 一道CCNA的简单题目
- 2018.1.13 LeetCode 47. Permutations II 60. Permutation Sequence 【STL简单应用】