洛谷 P1020 导弹拦截 最长上升子序列 LIS

 首先想到DP 

f[i] 表示 从 1 到  i 位 在选择 i 的情况下的最长上升子序列;

状态转移 :if(h[i]>=h[j]) f[i]=max(f[i],f[j]+1);   复杂度 (O) n²;

 优化 最长上升子序列 LIS 

此题求下降同理 

输入样例 389 207 155 300 299 170 158 65

输出样例 6 2

我们先模拟 过程

(1)389

(2)389 207

(3)389 207 155

(4)389 207 155

                300

(5)389 207 155

                300 299

(6)389 207 155

                300 299 170 

(7)389 207 155 158

                300 299 170 158

(8)389 207 155 158 65

                300 299 170 158 65

可以看出保证最优情况下出现两种分支

过程为

当遇到比当前最优序列最小值小的情况下 直接接入末尾,

当遇到比当前最优序列最小值大的情况下 说明出现分支 需要寻找 该值大小位置 保证他可以从某处接入当前序列 该点为分支点 但是当该分支长度可能还未超过已有序列,未来可能超过,

我们发现分支点值越大后面可接数列可能越长,故可以覆盖之前数字,只采用一维数组维护;

在寻找分支点时 可以二分查找优化

复杂度 (O) nlong(n);

#include
#include
#include
#include
#include
#include
using namespace std;
const int N=100005;
int n,ans;
int f[N],h[N];
int ask1(int k){
	int L=0,R=ans;
	while(L=k) {
			L=Mid; 
		}
		else R=Mid;
	}
	return R;
}
int ask2(int k){
	int L=0,R=ans;
	while(L=k) {
			L=Mid; 
			if(f[Mid]==k) return Mid;
		}
		else R=Mid;
	}
	return R;
}  
void Solve1(){
	ans=0; f[0]=N;
	for(int i=1;i<=n;i++){
		if(h[i]<=f[ans]) f[++ans]=h[i];
		else f[ask1(h[i])]=h[i];
	}
	printf("%d\n",ans);
}
void Solve2(){
	ans=0; f[0]=N;
	for(int i=1;i<=n;i++){
		if(h[i]

 

你可能感兴趣的:(动态规划)