[洛谷] P1020 导弹拦截

时间:2020-04-25
本文章向大家介绍[洛谷] P1020 导弹拦截 ,主要包括[洛谷] P1020 导弹拦截 使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目链接

O(n²)代码:

 1 #include <stdio.h>
 2 const int MAXN = 100005;
 3 int input[MAXN];
 4 int dec[MAXN];
 5 int inc[MAXN];
 6 int cnt = 0;
 7 int ans_max = 0;
 8 int ans_need = 0;
 9 int main()
10 {
11     //读入 
12     int tmp;
13     while(scanf("%d",&tmp) != EOF)
14     {
15         input[cnt++] = tmp;
16     }
17     //初始化
18     for(int i = 0;i < MAXN;i++)
19     {
20         dec[i] = 1;
21         inc[i] = 1;
22     }
23     //最长下降子序列
24     for(int i = cnt- 1;i >= 0;i--){
25         for(int j = i + 1;j < cnt;j++){
26             if(input[i] >= input[j]){
27                 if(dec[i] < dec[j] + 1)
28                 {
29                     dec[i] = dec[j] + 1;
30                 }
31             }
32         }
33         if(dec[i] > ans_max)
34             ans_max = dec[i];
35     }
36     printf("%d\n",ans_max);
37     
38 
39     //最长上升子序列
40     for(int i = 0;i < cnt;i++){
41         for(int j = i - 1;j >= 0;j--){
42             if(input[i] > input[j]){
43                 if(inc[i] < inc[j] + 1)
44                 inc[i] = inc[j] + 1;
45             }
46         }
47         if(ans_need < inc[i])
48             ans_need = inc[i];
49     }
50     printf("%d",ans_need);
51     return 0;
52 }
View Code

思路:

第一问:显然求最长不上升子序列长度即可,

第二问:求共能组成几条最长不上升子序列

Dilworth定理:偏序集的最少反链划分数等于最长链的长度(证明略)

就是求最长上升子序列

但是常规dp方法只有n²复杂度,此题只有100分(满分200)

O(nlogn)代码

  1 #include <stdio.h>
  2 #include <algorithm>
  3 using namespace std; 
  4 const int MAXN = 1000001;
  5 int n;
  6 int m;
  7 int array[MAXN];
  8 int tree[MAXN];
  9 void build(int tree[],int array[],int node,int start,int end)
 10 {
 11     if(start == end)    {
 12         
 13         tree[node] = 0;
 14     }
 15     else{
 16     
 17         int mid = (start + end) / 2;
 18         int left_node = 2 * node + 1;
 19         int right_node = 2 * node + 2;
 20         
 21         build(tree,array,left_node,start,mid);
 22         build(tree,array,right_node,mid + 1,end);
 23         tree[node] = max(tree[left_node], tree[right_node]);
 24     }
 25     
 26 }
 27 void update(int tree[],int array[],int node,int start,int end,int idx,int val)
 28 {
 29     if(start == end){
 30         tree[node] = val;
 31         return;
 32     }
 33     else
 34     {
 35         int mid = (start + end) / 2;
 36         int left_node = 2 * node + 1;
 37         int right_node = 2 * node + 2;
 38         if(idx >= start && idx <= mid){
 39             update(tree,array,left_node,start,mid,idx,val); 
 40         }
 41         else{
 42             update(tree,array,right_node,mid + 1,end,idx,val);
 43         } 
 44         tree[node] = max(tree[left_node] ,tree[right_node]);
 45     }
 46 }
 47 int query(int array[],int tree[],int node,int start,int end,int L,int R)
 48 {
 49     if(R < start || L > end){
 50     //    printf("start:%d,end:%d L:%d R:%d\n",start,end,L,R);
 51         return 0;
 52     }
 53     else if(start >= L && end <= R)
 54     {
 55     //    printf("start:%d,end:%d L:%d R:%d tree[%d] = %d\n return ",start,end,L,R,node,tree[node]);
 56         return tree[node];
 57     }
 58     else if(start == end){
 59     //        printf("start:%d,end:%d L:%d R:%d tree[%d] = %d\n",start,end,L,R,node,tree[node]);
 60         return tree[node];
 61     }
 62     else{
 63     //    printf("start:%d,end:%d L:%d R:%d tree[%d] = %d\n",start,end,L,R,node,tree[node]);
 64         int mid = (start + end) / 2;
 65         int left_node  = 2 * node + 1;
 66         int right_node = 2 * node + 2;
 67         int sum_left = query(array,tree,left_node,start,mid,L,R);
 68         int sum_right = query(array,tree,right_node,mid + 1,end,L,R);
 69         return max(sum_left, sum_right);
 70     }
 71  
 72      
 73 }
 74 int ans = 0;
 75 int cnt = 0;
 76 int max_height = 0;
 77 int main()
 78 {
 79     int tmp;
 80     while(scanf("%d",&tmp) != EOF)
 81     {
 82         array[cnt++] = tmp;
 83         if(tmp > max_height)
 84         max_height = tmp;
 85         
 86     }
 87     build(tree,array,1,1,max_height);
 88     for(int i = 0;i < cnt;i++)
 89     {
 90         int tmp = query(array,tree,1,1,max_height,array[i],max_height)+1;
 91         update(tree,array,1,1,max_height,array[i],tmp);
 92         if(tmp>ans) ans=tmp;
 93     }
 94     printf("%d\n",ans);
 95     
 96     ans=0;
 97     build(tree,array,1,1,max_height);
 98     for(int i = 0;i < cnt;i++)
 99     {
100         int tmp=query(array,tree,1,1,max_height,1,array[i] - 1)+1;
101         update(tree,array,1,1,max_height,array[i],tmp);
102         if (tmp>ans) ans=tmp;
103     }
104     printf("%d",ans);
105     return 0;
106 } 
View Code

思路:

1.重点是将高度值来当作线段树下标,而不是时间序

2.通过线段树来维护区间最长序列长度最大值

反思:线段树处理可以将输入数据离散化,若数据为1,2,200000,则不需要建呢么打树,只需要记录相对大小1,2,3也可得到相应答案

,为什么可以用线段树,一知半解注意透彻理解求LIS的过程。

原文地址:https://www.cnblogs.com/Ponytai1/p/12773477.html