A :导弹拦截
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意 的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所 有的导弹。
输入导弹一次飞来的高度(雷达给出的高度不大于30000的正整数)。计算这套系统最多能拦截多少导弹。
输入
n颗依次飞来的导弹高度,导弹颗数<=1000。
输出
一套系统最多拦截的导弹数。
样例输入
7
300 250 275 252 200 138 245
样例输出
5
Solution
一道经典的求最长不上升子序列的题目
N^2做法:dp[i]表示以i结尾的最长子序列长度
则dp[i]=max{dp[j]+1}(1<=j<i && a[i]<=a[j])
Nlogn做法:
首先,我们要想一种能够加速寻找j的方法
我们用s[i]表示长度为i的子序列的最后一个元素的值的最大值
即 s[i]=max{a[j]}(dp[j]=i)
可以看出,s[]数组必定是不上升的
假设有 s[i]<s[j] 且 i<j
那么长度为j的子序列中的第i个元素的值 d[i]>=d[j]=s[j]>s[i]
这与s数组的定义矛盾,
也就是说,s[i]的值应该是d[i],所以,s[j]必定<=s[i]
所以就可以二分,每次在s数组中找出
最后一个大于等于a[i]的值在s数组中的位置j
则dp[i]=j+1; s[j+1]=a[i];
CODE
CODE
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1010;
int dp[maxn],s[maxn],a[maxn];
int n,ans;
int my_binary_search(int l,int r,const int &key)
{
int mid,ans=l-1;
while (l<=r)
{
mid=(l+r)>>1;
if (s[mid]<key) r=mid-1;
else {ans=mid; l=mid+1;}
}
return ans;
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
cin>>a[i];
dp[0]=0; dp[1]=1; s[1]=a[1]; ans=1;
for (int i=2;i<=n;i++)
{
int j=my_binary_search(1,ans,a[i]);
dp[i]=j+1; s[j+1]=a[i];
if (j+1>ans) ans=j+1;
}
cout<<ans;
return 0;
}