zoukankan      html  css  js  c++  java
  • [bzoj3174][Tjoi2013]拯救小矮人

    DP+贪心


    前言

    说实话,我感觉网上大多数文章讲这篇都是在口胡,我发现znber同学的证明也是明显错误的(也许是我太蒻了).但有幸的是我遇上了这篇文章http://blog.csdn.net/commonc/article/details/51693992
    他跨了一年,做出了这道题,心疼QAQ。但我觉得他这篇还是没有多详细,搜索引擎也不容易先搜到他,于是就写了这篇辣鸡题解QAQ。


    题意

    我一开始一直纠结于“一个小矮人走后剩下的小矮人能不能重新组成梯子”。后面发现如果你把确定出去的小矮人直接依次排列,就可以不用重新组成了。所以这是一个没有意义的问题QAQ.所以我们现在的问题是,确定一个排列,
    使得最后的能够出去的人最多(根据我刚才所说,能出去的人一定排在最后)(我这里最后代表着梯子的最上面).


    求解第一步.贪心

    我们把最后的那一部分(即要出去的人)拿出来看,发现他们的这个序列的ai+bi是单调递减的.具体证明如下:
    如果有Ai与Aj相邻,且Ai在Aj的前面,Ai+Bi < Aj + Bj,此时的序列合法,那么我们需要证明把它们交换后此时的序列仍然合法.假设Ai前面的Ax的和是Sum.那么我们先看Ai,Ai+Sum+Bi是大于井深H的,我们交换后,Ai手伸出的高度变为Ai+Sum+Bi+Aj>Ai+Sum+Bi>H.显然依然合法.然后我们看Aj,他出去时高度变为Aj+Bj+Sum>Ai+Bi+Sum>H.也是合法的。


    求解第二步.Dp

    我们把原来序列从小到大排了以后,显然就能进行Dp了,我们可以注意到,对于一个矮人来说,如果他要被选的话,除了前面选了的矮人。其他所有的矮人都要被他踩在脚底,显然其他所有矮人高度最矮为好,这样他就能够踩得更高。那我们f[i][j]表示前i个位置选j个矮人,这j个矮人的最小高度和.然后就很好转移辣。还可以注意的是,这玩意儿是可以省掉前面一维的QAQ


    Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    const int N = 2e3 + 7, INF = 0x3f3f3f3f;
    char B[1 << 12], *S = B, *T = B;
    char getchar2 () { return S == T && (T = (S = B) + fread (B, 1, 1 << 12, stdin), S == T) ? -1 : *S++; }
    char pr[1 << 12], *pt = pr;
    void putchar2 (char x) { if (pt - pr == 1 << 12) fwrite (pr, 1, 1 << 12, stdout), pt = pr; *pt++ = x; }
    void G (int &num) {
        static char a;
        for (a = getchar2 (); a > '9' || a < '0'; a = getchar2 ()) ;
        for (num = 0; a >= '0' && a <= '9'; a = getchar2 ()) num = (num << 3) + (num << 1) + a - '0'; 
    }
    void print (int x) {
        static char stk[12]; static int top;
        if (!x) { putchar2 ('0'); putchar2 ('
    '); return ; }
        while (x) stk[++top] = x % 10 + '0', x /= 10;
        while (top) putchar2 (stk[top--]); putchar2 ('
    ');
    }
    
    void IO () {
        freopen ("3174.in", "r", stdin);
        freopen ("3174.out", "w", stdout);
    }
    
    int n, f[N], h, sum;
    
    struct item {
        int x, y;
        void init () { G (x); G (y); sum += x; }
        bool operator < (const item &rhs) const { return x + y < rhs.x + rhs.y; }
    }s[N];
    
    int main () {
    //  IO ();
        memset (f, 0x3f, sizeof (f));
        G (n); for (int i = 1; i <= n; ++i) s[i].init (); G (h);
        std :: sort (s + 1, s + n + 1); f[0] = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = i; j; --j) {
                if (sum - f[j - 1] + s[i].y >= h) f[j] = std :: min (f[j], f[j - 1] + s[i].x);
            }
        }
        for (int i = n; ~i; --i) if (f[i] != INF) {
            printf ("%d
    ", i);
            return 0;
        }
    }
  • 相关阅读:
    [linux]Linux下的log
    [WDT]内部看门狗和外部看门狗
    [misc]printf/fprintf/sprintf/snprintf函数
    [Linux]read/write和fread/fwrite有什么区别
    移动端图片操作(二)——预览、旋转、合成
    移动端图片操作(一)——上传
    实现tap的多种方式
    Hammer.js分析(四)——recognizer.js
    Hammer.js分析(三)——input.js
    Hammer.js分析(二)——manager.js
  • 原文地址:https://www.cnblogs.com/dcoi-king/p/7491428.html
Copyright © 2011-2022 走看看