12.29 洛谷1020 导弹拦截(寻找最长递减/增数列)

越往后学,你就越会知道,数学不好带来的苦痛与折磨。
这第二题要是不会数学没个做啊(大哭
第一问我本来想用动态规划做,但是感觉会爆。。毕竟六位数,n^2的时间复杂度。有人想用a[i][j]表示从i到j的递减数长度最大值,最后再逐次比较a[i][j]的大小……
哈哈哈,应该可行。但是还是nlogn的时间复杂度比较好啊。直接递减数列找然后二分的方法!简单而容易理解!!!耗时也少!妙哉,妙哉。
第二问等价于求一个最长递增数列。有人给出了证明,但我没怎么看懂,潸然泪下啊。

#include<iostream>
#include<memory.h>
#include<cstdio>
using namespace std;
int main()
{
	int a[100005];  int i=0,mid,r;
	while (scanf("%d", &a[i++]) != EOF)continue;
	i--;
	int f[100000] = { 1000000 };//f[0]得取一个大一点的数,不然可能比a[j]小。。就循环不了啦。
	int ans = 0, ans2 = 0;
	for (int j = 0; j <= i; j++)
	{
		if (f[ans] >= a[j])
		{
			f[++ans] = a[j];     //递减数列的创建过程
		}
		else
		{
			int p = 1; r = ans;
			while (p < r) {
				mid = (p + r) / 2;
				if (f[mid] >= a[i])p = mid + 1;
				else {
					r = mid;
				}
			}
			if (p != 1)f[p] = a[i];
		}                                   //二分查找新的数在递减数列中的位置,并替换原来的数
	}                    
	cout << ans << endl;
	memset(f, 0, sizeof(f));    //这里我本来想开一个新数组g[100001]的,奈何vs报错,估计是空间不够了
	for (int j = 0; j <= i; j++)
	{
		if (f[ans2] <= a[j])
		{
			f[++ans2] = a[j];
		}
		else
		{
			int p = 1; r = ans2;
			while (p < r) {
				mid = (p + r) / 2;
				if (f[mid] < a[i])p = mid + 1;
				else {
					r = mid;
				}
			}
			f[p] = a[i];
		}
	}
	
	cout << ans2;
	system("pause");
	return 0;

}

ok,写完了,我复习(yuxi)微积分去了。
1.2考试,菜鸡落泪

猜你喜欢

转载自blog.csdn.net/weixin_43484101/article/details/85451049