P1020 导弹拦截
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是\le 50000≤50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
11行,若干个整数(个数\le 100000≤100000)
输出格式
22行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出样例
输入
389 207 155 300 299 170 158 65
输出
6
2
早都对LIS有所了解,这道经典的题也早都写了,后来写LIS的题感觉LIS理解的一知半解,于是重新来学习。
不难看出这题分两问,是求解最长不上升子序列和最长上升子序列,在更新序列的时候分别用upper_bound()和lower_bound()这两个函数,分别是二分返回序列中第一个大于给定x的数(的地址)和二分返回序列中第一个大于等于给定x的数(的地址)。于是我就分不清用的时候这两个有什么区别,昨天一下午没想明白,夜里在床上想明白了。。。
最长不上升子序列在一个下降的序列中可以有相等的数,使用upper_bound()在已更新序列3 2 2 1中插入2,因为序列中可以有相等的,就把1代替为2。最长上升子序列中不能有相等的数,使用lower_bound()在已更新序列1 2 3中插入2,因为序列中不能有重复的,要把原序列的2代替为2。
没想明白之前就是想不通,想明白了就不难。。。
结论:
最长不上升子序列和最长不下降子序列用upper_bound();
最长上升子序列和最长下降子序列用lower_bound()。
upper_bound()和lower_bound()这两个函数默认查询増序的序列,降序的序列需自写比较函数或在最后一个参数上写上greater< int >()。如upper_bound(b+1,b+1+c,a[i],greater
#include
#include
#include
#include
using namespace std;
int v[100005],a[100005],b[100005],b1[100005];
bool cmp(int x,int y){
return x>y;
}
int main()
{
int n=0,m,i,j,k,x,y,t,c=1,c1=1,u,ans=0;
while(~scanf("%d",&a[++n]));//回车加ctrl+z结束
n--;
b[1]=b1[1]=a[1];
for(i=2;i<=n;i++){
if(a[i]<=b[c]) b[++c]=a[i];
else *upper_bound(b+1,b+1+c,a[i],cmp)=a[i];
if(a[i]>b1[c1]) b1[++c1]=a[i];
else *lower_bound(b1+1,b1+1+c1,a[i])=a[i];
}
printf("%d\n%d",c,c1);
return 0;
}
手写二分
#include
#include
#include
#include
using namespace std;
int v[100005],a[100005],b[100005],b1[100005];
int low(int r,int x){
int l=1;
while(l<=r){
int m=(l+r)/2;
if(b1[m]<x){
l=m+1;
}
else r=m-1;
}
return l;
}
int high(int r,int x){
int l=1;
while(l<=r){
int m=(l+r)/2;
if(b[m]<x){
r=m-1;
}
else l=m+1;
}
return l;
}
int main()
{
int n=0,i,c,c1;
while(~scanf("%d",&a[++n]));
n--;
b[1]=b1[1]=a[1];
for(i=2;i<=n;i++){
if(a[i]<=b[c]) b[++c]=a[i];
else b[high(c,a[i])]=a[i];
if(a[i]>b1[c1]) b1[++c1]=a[i];
else b1[low(c1,a[i])]=a[i];
}
printf("%d\n%d",c,c1);
return 0;
}