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;
        }
    }
  • 相关阅读:
    笨方法学python中执行argv提示ValueError: not enough values to unpack (expected 4, got 1)
    VMware workstation安装
    Redis bigkey分析
    MySQL drop table 影响及过程
    MySQL 大表硬连接删除
    ES elasticsearch 各种查询
    ES elasticsearch 各种聚合
    ES elasticsearch 聚合统计
    ES elasticsearch 实现 count单字段,分组取前多少位,以地理位置中心进行统计
    MySQL行溢出、varchar最多能存多少字符
  • 原文地址:https://www.cnblogs.com/dcoi-king/p/7491428.html
Copyright © 2011-2022 走看看