zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    快速幂取模
    程序人生系列之新闻发布系统 0105
    JavaWeb之博客系统(四)
    [转]树状数组
    题目:免费午餐
    题目:删数问题
    题目:三元组
    题目:分子团
    题目:[汪老师结婚]婚礼上的袭击
    题目:[SBN号码]
  • 原文地址:https://www.cnblogs.com/mogeko/p/10290600.html
Copyright © 2011-2022 走看看