导弹拦截——线性dp、dilworth定理、最长上升子序列

P1020 [NOIP1999 普及组] 导弹拦截 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道题和那个木棍加工的题让我懂了最长上升子序列的玩法。

这道题问了两个问题。

问题1:这套系统最多能拦截多少导弹

做法: 既然系统只能拦截不上升的序列。那么我们就求一下最长不上升子序列的长度。

   做法和最长上升子序列的做法一样,但是在二分的时候注意要使用upper_bound,理由是:我们求的是小于等于的数,那么等于a[i]的数就不用被挤出来啦,所以用upper。并且,因为求的是不上升子序列,应该是降序,但是upper与lower都只认识升序,所以我们要在使用他俩的时候upper_bound(f+1,f+1+cnt,a[i],greater() )-f。注意要加上greater(),或者用cmp表示递增也可。

 

问题2:如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

做法:根据dilworth定理,问题由最少分割为多少个不上升子序列转化为求该序列最长上升子序列的长度。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e5+100;
 4 int f[N],a[N],ff[N],ans1,ans2;
 5 
 6 
 7 int main()
 8 {
 9     int num,cnt=0;
10     while(~scanf("%d",&num))a[++cnt]=num;
11     //cnt--;
12     
13     f[1]=a[1],ff[1]=a[1],ans1=ans2=1;
14     for(int i=2;i<=cnt;i++)                //最长不上升子序列 
15     {
16         if(a[i]<=f[ans1])f[++ans1]=a[i];
17         else
18         {
19             int k=upper_bound(f+1,f+1+ans1,a[i],greater<int>() )-f;
20             f[k]=a[i];
21         }
22     }
23     printf("%d\n",ans1);
24     
25     for(int i=2;i<=cnt;i++)        //最长上升子序列 
26     {
27         if(a[i]>ff[ans2])ff[++ans2]=a[i];
28         else
29         {
30             int k=lower_bound(ff+1,ff+1+ans2,a[i])-ff;
31             ff[k]=a[i];
32         }
33     }
34     printf("%d\n",ans2);
35     
36     
37     return 0;
38 }
View Code

 

posted @ 2022-04-04 17:21  wellerency  阅读(79)  评论(0编辑  收藏  举报