传送门
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出格式
输入格式:
一行,若干个整数(个数少于100000)
输出格式:
2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出样例
输入样例:
389 207 155 300 299 170 158 65
输出样例:
View Code
6 2
solution:
这题是dp的基础题了,学过dp的应该都见过。就是求最长不下降子序列长度和最长上升子序列长度。
我们记f[i]为以i为最后一个数的时候的最优方案。并且记一个best[i]存储更新。每当有一个h[i]时,更新掉之前一个比它大的最后一个数,当前答案不变。
可能没有说得很清楚,所以直接上代码:
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 int n,m,ansa,ansb; 9 int h[100010],best[100010],d[100010]; 10 int fia(){ 11 int l,r,mid,cnt=0,ans; 12 int i,j; 13 memset(best,0,sizeof(best)); 14 best[++cnt]=h[1]; 15 for(i=2;i<=n;++i){ 16 if(h[i]<=best[cnt]) best[++cnt]=h[i]; 17 else{ 18 l=1;r=cnt; 19 while(l<=r){ 20 int mid=(l+r)>>1; 21 if(best[mid]<h[i]){ 22 r=mid-1;ans=mid; 23 } 24 else{ 25 l=mid+1; 26 } 27 } 28 best[ans]=h[i]; 29 } 30 } 31 return cnt; 32 } 33 int fib(){ 34 int l,r,mid,cnt=0,ans; 35 int i,j; 36 d[++cnt]=h[1]; 37 for(i=2;i<=n;++i){ 38 if(h[i]>d[cnt]) d[++cnt]=h[i]; 39 else{ 40 l=1;r=cnt; 41 while(l<=r){ 42 mid=(l+r)>>1; 43 if(d[mid]>=h[i]){ 44 r=mid-1;ans=mid; 45 } 46 else l=mid+1; 47 } 48 d[ans]=h[i]; 49 } 50 } 51 return cnt; 52 } 53 int main(){ 54 n=0; 55 while(scanf("%d",&h[++n])==1); 56 n--; 57 printf("%d\n",fia()); 58 printf("%d\n",fib()); 59 return 0; 60 }