P3902 递增--最长上升子序列:二分+贪心+动态规划

题目描述

现有数列A1,A2,⋯,ANA_1,A_2,\cdots,A_NA1​,A2​,⋯,AN​,修改最少的数字,使得数列严格单调递增。
输入格式

第1 行,1 个整数N

第2 行,N 个整数A1,A2,⋯,ANA_1,A_2,\cdots,A_NA1​,A2​,⋯,AN​
输出格式

1 个整数,表示最少修改的数字
输入输出样例
输入 #1

3
1 3 2

输出 #1

1

说明/提示

• 对于50% 的数据,N≤103N \le 10^3N≤103

• 对于100% 的数据,1≤N≤105,1≤Ai≤1091 \le N \le 10^5 , 1 \le A_i \le 10^91≤N≤105,1≤Ai​≤109

题解:因为提到使得数列变成严格单调递增,所以自然想到最长上升子序列,求出最长上升子序列长len度然后直接输出n-len就为答案,最长上升子序列就是动态规划问题,但是这个题目数据量n<=100000比较大,所以不能用一般的动态规划,得用贪心和二分处理一下。

AC代码

#include
using namespace std;
vectorb;
int fin_pos(int x)
{
	int l=0,r=b.size()-1;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(b[mid]>=x)
		r=mid-1;
		else l=mid+1;
	}
	return l;
}
int main()
{
	int n;
	cin>>n;
	//动态数组b储存构成的最长上升子序列
	b.clear();
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		if(i==1)
		{
			b.push_back(x);
			continue;
		}
		int m=b.size();
		//如果新输入的数字比储存在数组b末尾的数字大,符合单调递增直接加入动态数组b
		if(x>b[m-1])
		b.push_back(x);
		//否则,用贪心思想,我们进行数据修改,使得动态数组里储存的单独递增的元素之间差值尽可能小,这样在
		//后期遇到其他数字能有更大的变化空间,所以我们找到动态数组b中第一个大于等于x的元素位置sign,并更新b[sign]=x;
		else{
			int sign=fin_pos(x);
			b[sign]=x;	
		}
	}
	//直接输出答案
	printf("%d\n",n-b.size());
	return 0;
}

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