题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是\le 50000≤50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
11行,若干个整数(个数\le 100000≤100000)
输出格式
22行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出样例
389 207 155 300 299 170 158 65
6 2
说明/提示
为了让大家更好地测试n方算法,本题开启spj,n方100分,nlogn200分
看了几篇博客,讲的都是最长上升子序列的nlogn 解法:只是简单的讲了是 贪心+DP
贪心 :大部分是这样证明的:
当你从一串数中构造一个最长子序列,在选择数时 要尽量选择最大的数字作为下一个数字,因为大的数字为后续选择提供了更多选择,从而使序列变得更长;
当你这次选的数字比正在构造的最后一个数字大时,找到比你这次选的数字小于等于的地方,用这个数字替换原先存在的数字,而且,在这个替换的数字后的数字不要删掉。
形如下面这个样例:
这个样例展示的是《《《最长不上升子序列》》》
一组样例: //90 103 99 83 102 70 86 70 99 71 //结果是:5
在构造的序列变化是:
90
103
103 99
103 99 83
103 102 83
103 102 83 70
103 102 86 70
103 102 86 70 70
103 102 99 70 70
103 102 99 71 70 //显然最后得到的不一定是真实应该得到的子序列;
103 99 83 70 70//真实应该得到的子序列
明显可以看出:真实的子序列中的数字都是曾经在此位置的数字。
将这个位置替换,其实只是在原先位置更换了一个新的用于比较的标签,因为这个新的标签更大,为后边提供了更长的可能。
此题AC代码:lower_bound(begin(),end(),x,greater<int>()); 通过greater<int>()改变比较方向。
#include<iostream> #include<vector> #include<algorithm> using namespace std; vector<int>a,b,c; int main () { int num,n=0; while(cin>>num) { n++; a.push_back(num); } n--; for(int i=0;i<=n;i++) { int it=upper_bound(b.begin(),b.end(),a[i],greater<int>())-b.begin(); //cout<<it<<endl; if(it==b.size()) b.push_back(a[i]); else { b[it]=a[i]; } int itn=lower_bound(c.begin(),c.end(),a[i])-c.begin(); if(itn==c.size()) c.push_back(a[i]); else c[itn]=a[i]; } //for(auto itm:b) // cout<<itm<<endl; cout<<b.size()<<endl; cout<<c.size(); return 0; }