最长上升子序列变形问题:
1.UVA10534 Wavio Sequence
https://vjudge.net/contest/368513#problem/A
寻找一个a[i],使得i之前有n个a[j]使得a[j]<a[i],j<i,i之后有n个a[j]<a[i],j>i
寻找最大长度n
解题思路:
①正序进行一个求最长上升子序列,在low数组中更新最长子序列,每更新一个点,用dp1记下这个点在low数组中的位置,这个位置就是它正序最长上升子序列长度
②逆序进行一个求最长上升子序列,在high数组中更新最长子序列,每更新一个点,用dp2记下这个点在high数组中的位置,这个位置就是它逆序 最长上升子序列长度
③最终答案就是遍历每个点的满足条件的最大长度 min(dp1[i],dp2[i])*2-1
#include<iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
int n;
int a[11000];
int low[11000],high[11000];
int dp1[11000],dp2[11000];
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(low,0,sizeof(low));
memset(high,0,sizeof(high));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
low[1]=a[1];
dp1[1]=1;
int ans=1;
for(int i=2;i<=n;i++)
{
if(a[i]>low[ans])
low[++ans]=a[i],dp1[i]=ans;
else
{
int j=lower_bound(low+1,low+ans+1,a[i])-low;
low[j]=a[i];
dp1[i]=j;
}
}
high[1]=a[n];
dp2[n]=1;
ans=1;
for(int i=n-1;i>0;i--)
{
if(a[i]>high[ans])
high[++ans]=a[i],dp2[i]=ans;
else
{
int j=lower_bound(high+1,high+ans+1,a[i])-high;
high[j]=a[i];
dp2[i]=j;
}
}
ans=0;
for(int i=1;i<=n;i++)
ans=max(min(dp1[i],dp2[i]),ans);
ans=ans*2-1;
cout<<ans<<endl;
}
return 0;
}
2.UVA1471 Defense Lines
https://vjudge.net/contest/368513#problem/B
删除一个连续子序列,然后寻找最大的删除后的字符串中最长连续上升子序列。
解题思路:
①先正序寻找以i为结尾的连续上升子序列长度,保存在p数组中;再逆序寻找以i为开头的连续上升子序列长度,保存在f数组中。
②用d[i]记录长度为i的连续上升子序列的结尾大小,而且当不同结尾大小对应相同长度i的连续上升子序列时,d[i]取小的结尾
for(int i=0;i<n;i++)
{
int j=lower_bound(d+1,d+i+1,a[i])-d;
//对于i来言,d中保存的结尾都是在i之前的,可以通过删除到达
//而且d中保存的最大长度也只能是i,所以只需要利用二分搜索到d+i就可以
int len=j+f[i]-1;
ans=max(ans,len);
d[p[i]]=min(a[i],d[p[i]]); //相同长度上升连续子序列取小的结尾保存
}
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long
int n;
int a[210000];
int d[210000];
int f[210000];
int p[210000];
int main()
{
int t;
cin>>t;
while(t--)
{
memset(d,0,sizeof(d));
memset(f,0,sizeof(f));
memset(p,0,sizeof(p));
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
p[0]=1;f[n-1]=1;
for(int i=1;i<n;i++)
{
if(a[i]>a[i-1])
p[i]=p[i-1]+1;
else
p[i]=1;
d[i]=1100000000;
}
d[n]=1100000000;
for(int i=n-2;i>=0;i--)
{
if(a[i]<a[i+1])
f[i]=f[i+1]+1;
else
f[i]=1;
}
int ans=0;
for(int i=0;i<n;i++)
{
int j=lower_bound(d+1,d+i+1,a[i])-d;
int len=j+f[i]-1;
ans=max(ans,len);
d[p[i]]=min(a[i],d[p[i]]);
}
printf("%d\n",ans);
}
return 0;
}