导弹拦截

来源:互联网 发布:剑网3菊花插件dbm数据 编辑:程序博客网 时间:2024/05/18 03:49

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; }