线性DP汇总(持续更新)

最长上升子序列变形问题:
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;
}
原创文章 65 获赞 3 访问量 2091

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/105613872