nlogn求最长不上升子序列
这种问题一般都比较熟悉,我们先看n^2的算法
导弹拦截
时间限制: 1 Sec 内存限制: 128 MB提交: 106 解决: 61
[提交][状态][讨论版]
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意 的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所 有的导弹。
输入导弹一次飞来的高度(雷达给出的高度不大于30000的正整数)。计算这套系统最多能拦截多少导弹。
输入
n颗依次飞来的导弹高度,导弹颗数<=1000。
输出
一套系统最多拦截的导弹数。
样例输入
7
300 250 275 252 200 138 245
样例输出
5
令f[i]表示前i个数的最长序列长度f[j]=max(f[j],f[i]+1)i<j且a[i]>=a[j]
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,a[1005],f[1005],ans; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { f[i]=1; for(int j=1;j<i;j++) if(a[j]>=a[i])f[i]=max(f[i],f[j]+1); } for(int i=1;i<=n;i++) ans=max(ans,f[i]); cout<<ans<<endl; }
但是在一些n=100000的题目上O(n^2)的算法会时间超限。我们考虑优化这一算法。令B[i]=长度位i的序列最后一个一个字符的最大值。
对于新进来的一个数,我们看其能否跟新B数组中的一个值。如何跟新一个值呢?二分查找。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,B[100005],a[100005],len; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); B[1]=-a[1],len=1; for(int i=2;i<=n;i++) { if(-a[i]>=B[len]) B[++len]=-a[i]; else { int pos=upper_bound(B+1,B+len,-a[i])-B; B[pos]=-a[i]; } } cout<<len<<endl; }
就是很短的代码实现了nlogn的类lis功能。