Wavio Sequence UVA - 10534
最长上升子序列
题目描述:给了一个定义的序列Wavio,该序列的定义是:长度为2*n + 1,前n+1个数是严格递增的,后n+1个数是严格递减的,且相邻两个数不重复。求最长的Wavio序列的长度。
解题分析:数据量是10000,显然n*n的算法行不通,必须得用n*logn的算法。在本题中我的解法是,正序求最长上升子序列,逆序再求一遍,分别记录上升序列的最小下标,算完两个序列后,只要判断两个上升序列没有交差,那这个序列就是Waviox序列,更新最大值即可。在此处不用判断两个上升序列的最大值是否相等,因为如若不等,总可以让其中一个大的上升序列的最大值来替换小的那个上升序列的最大值。例如序列是1 2 4 7 和 9 8 2 1 ,只需要让第一个序列的最大值变为9就可以满足是Wavio序列了,前提是两个序列没有交叉。判断两个序列没有交叉就是判断的这两个序列的最大值的最小下标和是否>= N,如果不,则不交叉。
代码如下:
手写二分查找版
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 10000 + 10;
int num[maxn];
int dp1[maxn];
int dp2[maxn];
int index1[maxn];
int index2[maxn];
int bin_s(int t,int len,int * dp)
{
int l = 0,r = len + 1;
int ans;
while(r - l > 1)
{
int mid = (l + r) / 2;
if(dp[mid] >= t)
{
r = mid;
ans = mid;
}
else
{
l = mid;
}
}
return ans;
}
int main()
{
int N;
while(scanf("%d",&N)!=EOF)
{
for(int i = 0; i < N; i++)
{
scanf("%d",&num[i]);
}
memset(dp1,0x3f,sizeof(dp1));
memset(dp2,0x3f,sizeof(dp2));
int len = 1;
dp1[1] = num[0];
index1[len] = 0;
for(int i = 1; i < N; i++)
{
if(num[i] > dp1[len])
{
dp1[++len] = num[i];
index1[len] = i;
}
else
{
int t = bin_s(num[i],len,dp1);
dp1[t] = num[i];
}
}
reverse(num,num + N);
len = 1;
dp2[1] = num[0];
index2[len] = 0;
for(int i = 1; i < N; i++)
{
if(num[i] > dp2[len])
{
dp2[++len] = num[i];
index2[len] = i;
}
else
{
int t = bin_s(num[i],len,dp2);
dp2[t] = num[i];
}
}
int ans = -1;
for(int i = 1; i <= N; i++)
{
if(dp1[i] == INF ||dp2[i] == INF) continue;
if(index1[i] + index2[i] >= N) continue;
ans = max(ans,i);
}
cout << 2 * ans - 1 << endl;
}
return 0;
}
lower_bound版
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 10000 + 10;
int num[maxn];
int dp1[maxn];
int dp2[maxn];
int index1[maxn];
int index2[maxn];
int main()
{
int N;
while(scanf("%d",&N)!=EOF)
{
for(int i = 0; i < N; i++)
{
scanf("%d",&num[i]);
}
memset(dp1,0x3f,sizeof(dp1));
memset(dp2,0x3f,sizeof(dp2));
for(int i = 0; i < N; i++)
{
int t = lower_bound(dp1,dp1 + N,num[i]) - dp1;
if(dp1[t] == INF) index1[t] = i;
dp1[t] = num[i];
}
reverse(num,num + N);
for(int i = 0; i < N; i++)
{
int t = lower_bound(dp2,dp2 + N,num[i]) - dp2;
if(dp2[t] == INF) index2[t] = i;
dp2[t] = num[i];
}
int ans = -1;
for(int i = 0; i < N; i++)
{
if(dp1[i] == INF ||dp2[i] == INF) continue;
if(index1[i] + index2[i] >= N) continue;
ans = max(ans,i + 1);
}
cout << 2 * ans - 1 << endl;
}
return 0;
}