题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出格式
输入格式:
一行,若干个整数(个数少于100000)
输出格式:
2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出样例
输入样例#1:
389 207 155 300 299 170 158 65
输出样例#1:
6
2
说明
复杂度: nlogn
Dilworth定理
在一个序列中 最长下降子序列的个数就等于其最长不下降子序列的长度
所以呢这题就是求最长不上升子序列长度和最长上升子序列长度
upperbound,lowerbound写法
#include<bits/stdc++.h> using namespace std; #define maxn 100005 #define inf 0x3f3f3f3f int dp1[maxn],dp2[maxn]; int n=0,a[maxn]; int len1,len2; int cmp(int x,int y) { return x>y; } int main() { while(scanf("%d",&a[++n])!=EOF); n--;//处理EOF的那一次 fill(dp2,dp2+n+1,inf); len1=1; len2=1; for(int i=1; i<=n; i++) { int k1=upper_bound(dp1+1,dp1+1+n,a[i],cmp)-dp1; int k2=lower_bound(dp2+1,dp2+1+n,a[i])-dp2; dp1[k1]=a[i]; dp2[k2]=a[i]; len1=max(len1,k1); len2=max(len2,k2); } cout<<len1<<endl<<len2; return 0; }
直接二分写
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> using namespace std; #define maxn 300000+5 const int inf=0x3f3f3f3f; int a[maxn]; int n=0; int dp1[maxn],dp2[maxn]; int len1=0,len2=0; //寻找刚好小于x的下标 int pos1(int l,int r, int x) { if(x<=dp1[len1]) return len1=len1+1; while(l < r) { int m = l + (r-l)/2; if(dp1[m] >= x) //千万别写成a[m],脑袋要清晰点 l = m + 1; else r = m; } return r; } //寻找大于等于x的下标 int pos2(int l,int r,int x) { if(x>dp2[len2]) return len2=len2+1; while(l<r) { int m=l+((r-l)>>1); if(dp2[m]<x) l=m+1; else r=m; } return r; } int main() { while(scanf("%d",&a[++n])!=EOF); n--; dp1[0]=inf; dp2[0]=-inf; for(int i=1; i<=n; i++) { int k1=pos1(1,len1,a[i]); int k2=pos2(1,len2,a[i]); dp1[k1]=a[i]; dp2[k2]=a[i]; } cout<<len1<<endl<<len2; return 0; }