/* 返回顶部 */

Luogu P1020 导弹拦截

传送门

这道题信息量好大啊

1.Dilworth定理

  •   Dilworth定理:对于一个偏序集,最少链划分等于最长反链长度。
  •   Dilworth定理的对偶定理:对于一个偏序集,其最少反链划分数等于其最长链的长度。

  其实就是说,对于一个序列,

  最大上升子序列长度 = 不上升子序列个数,最大不上升子序列长度 = 上升子序列个数,

  最大下降子序列长度 = 不下降子序列个数,最大不下降子序列长度 = 下降子序列个数。

  所以这道题:Q1求最大不上升子序列长度,Q2求不上升子序列个数 = 最大上升子序列长度。

2.STL函数:lower_bound( )和upper_bound( )

lower_bound(num,num+L,A)-num; //返回第一个 >=A 的值
upper_bound(num,num+L,A)-num; //返回第一个 >A 的值
lower_bound(num,num+L,A,greater<int>())-num; //返回第一个 <=A 的值 
upper_bound(num,num+L,A,greater<int>())-num; //返回第一个 <A 的值

  只能在单调序列里调用,从前往后找

  lower是>=,upper是>,用greater或者cmp改成<= / <

  得到的是元素的地址,最后减去数组的地址就得到了元素下标。

  其实就是代替了二分查找...二分的写法见P1439 【模板】最长公共子序列

  需要调用<algorithm>库,如果用greater还要调用<iostream>

 

注意:

1.读入时

while(scanf("%d",&a[++n])!=EOF) {
        continue;
    }
    n--;

因为是先进行++n操作再判断的,所以多了一次,最后要n--.

2.Q1每次要求更小的,所以up1[0]要赋值为INF,不能为0.

 

代码如下

动态规划( O(n^2),100分 )

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn = 200005;
int n,ans,a[maxn],f[maxn],g[maxn];
int main() {
    while(scanf("%d",&a[++n])!=EOF) {
        f[n] = 1;
        g[n] = 1;
    }
    for(int i = n; i >= 1; i--)
        for(int j = i+1; j <= n; j++)
            if(a[i] >= a[j])
                f[i] = max(f[i],f[j]+1);
    for(int i = 1; i <= n; i++)
        ans = max(ans,f[i]);
    printf("%d\n",ans);
    ans = 0;
    for(int i = n; i >= 1; i--)
        for(int j = i+1; j <= n; j++)
            if(a[i] < a[j])
                g[i] = max(g[i],g[j]+1);
    for(int i = 1; i <= n; i++)
        ans = max(ans,g[i]);
    printf("%d\n",ans);
    return 0;
}
View Code

正解( O(nlogn),200分 )

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 200005;
int n,ans,a[maxn],up1[maxn],up2[maxn];
int main() {
    while(scanf("%d",&a[++n])!=EOF) {
        continue;
    }
    n--;
    up1[0] = maxn;
for(int i = 1; i <= n; i++) {
        if(a[i] <= up1[ans])
            up1[++ans] = a[i];
        else {
            int k = upper_bound(up1+1,up1+ans+1,a[i],greater<int>())-up1;
            up1[k] = a[i];
        }
    }
    printf("%d\n",ans);
    ans = 0;
    up2[1] = a[1];
    for(int i = 1; i <= n; i++) {
        if(a[i] > up2[ans])
            up2[++ans] = a[i];
        else {
            int k = lower_bound(up2+1,up2+ans+1,a[i])-up2;
            up2[k] = a[i];
        }
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

posted @ 2019-01-19 10:10  Mogeko  阅读(213)  评论(0编辑  收藏  举报