zoukankan      html  css  js  c++  java
  • 合并果子(单调队列优化)

      题意:

      n堆果子,每次可以选择两堆果子并将其合并成一堆果子,代价为新生成一堆的果子数。问最终合并成一堆的最小代价。(n<=1e5,Si<=2e5)(Si表示第i堆的果子数)

      题解:

      其实这题做法有很多。可以O(n^3)动规,可以O(n^2*logn)贪心,也可以用堆优化使得贪心的复杂度降到O(n*logn)。

      但其实还有一种O(n)的合并方法——单调队列。

      我们维护两个队列q1,q2,其中q1表示原本的那些堆(初始按升序排序),每次新合成的果子加入q2队尾。因为新合成的堆是越来越大的,所以q2也是有序的。那么我们很容易就可以从q1和q2中选出最小的两堆进行合并。

      但是一开始题目给你的序列显然不是有序的对吧。如果用快排的话总复杂度就是O(n*logn+n),还不如堆优化。那么我们考虑桶排序,就可以把复杂度降为O(n+S)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define LL long long
    #define RI register int
    using namespace std;
    const int INF = 0x7ffffff ;
    const int N = 10000 + 10 ;
    const int M = 20000 + 10 ;
    
    inline int read() {
        int k = 0 , f = 1 ; char c = getchar() ;
        for( ; !isdigit(c) ; c = getchar())
          if(c == '-') f = -1 ;
        for( ; isdigit(c) ; c = getchar())
          k = k*10 + c-'0' ;
        return k*f ;
    }
    int n ; int num[M+10], hh[N] ;
    deque<int>q1 ;
    deque<int>q2 ;
    
    int main() {
        n = read() ;
        int x, y, ans = 0, mx = -INF ;
        memset(num,0,sizeof(num)) ;
        for(int i=1;i<=n;i++) {
            x = read() ;
             num[x]++ ;
             mx = mx > x ? mx : x ;
        }
        for(int i=1;i<=mx;i++) {
            while(num[i]) {
                q1.push_back(i) ; num[i] -- ;
            }
        }
        for(int i=1;i<n;i++) {
            if(!q2.size()) x = q1.front(), q1.pop_front() ;
            else if(!q1.size()) x = q2.front(), q2.pop_front() ;
            else {
                if(q1.front() < q2.front()) {
                    x = q1.front(), q1.pop_front() ;
                } else x = q2.front(), q2.pop_front() ;
            }
            if(!q2.size()) y = q1.front(), q1.pop_front() ;
            else if(!q1.size()) y = q2.front(), q2.pop_front() ;
            else {
                if(q1.front() < q2.front()) {
                    y = q1.front(), q1.pop_front() ;
                } else y = q2.front(), q2.pop_front() ;
            }
            ans += (x+y) ;
            q2.push_back(x+y) ;
        }
        printf("%d",ans) ;
        return 0 ;
    }
    View Code

    ——end ;

  • 相关阅读:
    sql DATEDIFF 函数
    电控宝 命令
    dart 函数练习
    json对象和json字符串有啥区别啊
    windows 下 node 入门
    windows 下Nginx 入门
    SQL十进制和十六进制相互转换
    Action向视图传值的6种方式(转)
    从匿名方法到 Lambda 表达式的推演过程
    vue 入门1 组件管理
  • 原文地址:https://www.cnblogs.com/zub23333/p/8568544.html
Copyright © 2011-2022 走看看