题目:
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
Input
一行,若干个整数,中间由空格隔开。
Output
两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
思路:
最长和最长不升序子序列问题。
最多拦截《==》最长不上升序子序列。
最少需要多少系统拦截《==》最长上升子序列
优化:
比如最长上升子序列问题,对于a[i]以前的子序列,当a[k]<a[i](k<i)时,dp[i]=max(dp[k]+1,dp[i]),但时间复杂度高。可以记录每种长度的子序列最后一个数(建一个数组b[],他的数是严格递增的),当a[i]>b[j],a[i]就可以排在b[j]后边,找到满足a[i]>b[j]条件的最后一个j,b[j+1]=a[i],长度len=max(len,j+1),最后答案即为len(len为最长子序列有多少个数;
最长不上升序子序列一样,当a[i]<=b[j],a[i]就可以排在b[j](他的数是不上升的)后边,找到满足a[i]>b[j]条件的最后一个j,b[j+1]=a[i],长度len=max(len,j+1),最后答案即为len(len为最长不上升序子序列有多少个数);
需要注意b[0]的取值,他一定要让a[i]满足和b[j]关系,比如最长子序列a[i]>b[0],最长不升a[i]<=b[0];
代码:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#include<algorithm>
#include<cmath>
#include<map>
#include<string.h>
#include<string>
#include<cstring>
using namespace std;
const long long N=1e6;
const long long MAX = 1e13;
long long n,m, a[N],b[N],l,r,mid,c[N],ans,cnt;
int main()
{
while (cin >> ans)
a[++cnt] = ans;
long long len = 0;
long long len1 = 0;
b[0] = -MAX;
for (int i = 1; i <= cnt; i++)
{
l = 0;
r = len;
while (l <= r)
{
mid = (l + r) / 2;
if (b[mid] < a[i])
ans = mid, l = mid + 1;
else
r = mid - 1;
}
b[ans + 1] = a[i];
len = max(len, ans + 1);
}
c[0] = MAX;
for (int i = 1; i <= cnt; i++)
{
l = 0;
r = len1;
while (l <= r)
{
mid = (l + r) / 2;
if (a[i] <= c[mid])
ans = mid, l = mid + 1;
else
r = mid - 1;
}
c[ans + 1] = a[i];
len1 = max(len1, ans + 1);
}
cout << len1 << endl;
cout << len << endl;
return 0;
}