这道题看起来不难,本来没看数据大小,写了一个n^2的最长上升子序列常规解法,结果超时了。回来一看这数据量确实有点大。
然后发现这道题用到的是最长上升子序列的nlogn解法,不太了解的同学可以参见我这篇博客。https://blog.csdn.net/a1097304791/article/details/82286906
然后把小于0的数去掉,大于等于10000连写5遍就可以直接套板子了
//最重非递减子序列
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 1e6+5;
int a[MAXN], b[MAXN];
//用二分查找的方法找到一个位置,使得num>b[i-1] 并且num<b[i],并用num代替b[i]
int Search(int num, int low, int high) {
int mid;
while(low <= high) {
mid = (low + high) / 2;
if(num >= b[mid])
low = mid + 1;
else
high = mid - 1;
}
return low;
}
int DP(int n) {
int i, len, pos;
b[1] = a[1];
len = 1;
for(i = 2; i <= n; i++) {
if(a[i] >= b[len]) { //如果a[i]比b[]数组中最大还大直接插入到后面即可
len = len + 1;
b[len] = a[i];
} else { //用二分的方法在b[]数组中找出第一个比a[i]大的位置并且让a[i]替代这个位置
pos = Search(a[i], 1, len);
b[pos] = a[i];
}
}
return len;
}
int main() {
int input, index = 1;
memset(a, 0, sizeof(a));
while(scanf("%d", &input) != EOF) {
a[index] = input;
if(input < 0) //把负数直接去掉
index--;
else if(input >= 10000) { //把后5个数全变为input-10000
for(int i = index; i <= index+4; i++)
a[i] = input - 10000;
index+=4;
}
index++;
}
printf("%d\n",DP(index-1));
return 0;
}
也附上模板,实在不了解的同学记一下模板下次直接用就行。
const int MAXN = 500010;
int a[MAXN], b[MAXN];
//用二分查找的方法找到一个位置,使得num>b[i-1] 并且num<b[i],并用num代替b[i]
int Search(int num, int low, int high) {
int mid;
while(low <= high) {
mid = (low + high) / 2;
if(num >= b[mid])
low = mid + 1;
else
high = mid - 1;
}
return low;
}
int DP(int n) {
int i, len, pos;
b[1] = a[1];
len = 1;
for(i = 2; i <= n; i++) {
if(a[i] >= b[len]) { //如果a[i]比b[]数组中最大还大直接插入到后面即可
len = len + 1;
b[len] = a[i];
} else { //用二分的方法在b[]数组中找出第一个比a[i]大的位置并且让a[i]替代这个位置
pos = Search(a[i], 1, len);
b[pos] = a[i];
}
}
return len;
}