DP - 最长上升子序列(nlogn模板) - Wavio Sequence - UVA - 10534
题意:
多 组 测 试 数 据 , 每 组 包 括 一 个 长 度 为 n 的 序 列 。 多组测试数据,每组包括一个长度为n的序列。 多组测试数据,每组包括一个长度为n的序列。
求 这 个 序 列 中 最 长 的 “ 凸 ” 序 列 的 长 度 。 求这个序列中最长的“凸”序列的长度。 求这个序列中最长的“凸”序列的长度。
“ 凸 ” 序 列 : 先 严 格 递 增 , 再 严 格 递 减 , 且 递 增 的 长 度 与 递 减 的 长 度 相 同 。 “凸”序列:先严格递增,再严格递减,且递增的长度与递减的长度相同。 “凸”序列:先严格递增,再严格递减,且递增的长度与递减的长度相同。
举例:
1 2 3 2 1 2 3 4 3 2 1 5 4 1 2 3 2 2 1
the longest Wavio sequence is : 1 2 3 4 5 4 3 2 1
元 素 5 的 左 侧 严 格 递 增 的 长 度 为 5 , 右 侧 严 格 递 减 的 长 度 为 5 , 总 长 度 为 2 × 5 − 1 = 9 。 元素5的左侧严格递增的长度为5,右侧严格递减的长度为5,总长度为2×5-1=9。 元素5的左侧严格递增的长度为5,右侧严格递减的长度为5,总长度为2×5−1=9。
Sample Input:
10
1 2 3 4 5 4 3 2 1 10
19
1 2 3 2 1 2 3 4 3 2 1 5 4 1 2 3 2 2 1
5
1 2 3 4 5
Sample Output:
9
9
1
数据范围:
1 < = n < = 10000 T i m e l i m i t : 3000 m s 1<=n<=10000\\Time\ limit:3000 \ ms 1<=n<=10000Time limit:3000 ms
分析:
与——《DP - 最长上升子序列模型 - NOIP2004提高组 - 合唱队形 + 北京大学ACM/ICPC选拔赛 - 登山》类似。
区 别 在 于 : 本 题 要 求 中 心 两 侧 单 调 的 序 列 长 度 相 同 。 区别在于:本题要求中心两侧单调的序列长度相同。 区别在于:本题要求中心两侧单调的序列长度相同。
那 么 与 上 述 模 型 类 似 的 , 正 反 两 遍 做 最 长 上 升 子 序 列 后 , 对 中 心 i , 要 取 i 左 侧 严 格 递 增 序 列 长 度 与 右 侧 严 格 递 减 序 列 长 度 的 较 小 值 r e s 。 最 终 结 果 应 当 是 2 × r e s − 1 。 那么与上述模型类似的,正反两遍做最长上升子序列后,\\对中心i,要取i左侧严格递增序列长度与右侧严格递减序列长度的较小值res。\\最终结果应当是2×res-1。 那么与上述模型类似的,正反两遍做最长上升子序列后,对中心i,要取i左侧严格递增序列长度与右侧严格递减序列长度的较小值res。最终结果应当是2×res−1。
需要注意的是:
本 题 数 据 范 围 是 10000 , 因 此 O ( n 2 ) 的 朴 素 写 法 被 卡 掉 了 , 要 用 单 调 队 列 + 二 分 优 化 。 本题数据范围是10000,因此O(n^2)的朴素写法被卡掉了,要用单调队列+二分优化。 本题数据范围是10000,因此O(n2)的朴素写法被卡掉了,要用单调队列+二分优化。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=10010;
int n,a[N],f1[N],f2[N];
int main()
{
while(~scanf("%d",&n))
{
memset(f1,0,sizeof f1);
memset(f2,0,sizeof f2);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int q[N];
q[0]=-1e9;int len=0;
for(int i=1;i<=n;i++)
{
int l=0,r=len;
while(l<r)
{
int mid=l+r+1>>1;
if(q[mid]<a[i]) l=mid;
else r=mid-1;
}
len=max(len,r+1);
f1[i]=r+1;
q[r+1]=a[i];
}
memset(q,0,sizeof q);
q[0]=-1e9;len=0;
for(int i=n;i;i--)
{
int l=0,r=len;
while(l<r)
{
int mid=l+r+1>>1;
if(q[mid]<a[i]) l=mid;
else r=mid-1;
}
len=max(len,r+1);
f2[i]=r+1;
q[r+1]=a[i];
}
int res=1;
for(int i=1;i<=n;i++) res=max(res,min(f1[i],f2[i]));
printf("%d\n",2*res-1);
}
return 0;
}