• bzoj1345 序列问题


    题意:

    给你一个序列,长度为n。你需要进行n - 1次操作,每次合并两个相邻的数,代价是max,合并后成为max,求最小代价。

    n <= 1e6

    解:

    有个显然的做法是nlogn的,显然不行...

    要搞个O(n)的算法,显然是贪心。

    然而想不出来...

    主要有两种思路。

    ①合并成一颗树。从根向下考虑。

    根的贡献就是他的子节点数。

    然后问题递归。

    我们还可以证明有一种最优解,每个位置的数至多被合并2次。

    那么就是一颗大根堆。

    也可以说:若一个数的旁边比他小,那么一定会有一次合并过来,贡献为他自己。

    所以做法就是:每个数的贡献是他两边比他小的个数。

    ②由于每次要合并小的,就开个单调栈,下面大。

    每次出栈时合并,最后再合并栈中的数即可。


    记得开long long

     1 #include <cstdio>
     2 #include <algorithm>
     3 typedef long long LL;
     4 const int N = 1000010;
     5 
     6 int a[N];
     7 
     8 int main() {
     9     int n;
    10     scanf("%d", &n);
    11     if(n == 1) {
    12         scanf("%d", &a[1]);
    13         printf("0");
    14         return 0;
    15     }
    16     if(n == 2) {
    17         scanf("%d%d", &a[1], &a[2]);
    18         printf("%d", std::max(a[1], a[2]));
    19         return 0;
    20     }
    21     scanf("%d%d", &a[1], &a[2]);
    22     LL ans = 0;
    23     if(a[1] > a[2]) {
    24         ans += a[1];
    25     }
    26     for(int i = 3; i <= n; i++) {
    27         scanf("%d", &a[i]);
    28         if(a[i - 1] > a[i - 2]) {
    29             ans += a[i - 1];
    30         }
    31         if(a[i - 1] > a[i]) {
    32             ans += a[i - 1];
    33         }
    34     }
    35     if(a[n] > a[n - 1]) {
    36         ans += a[n];
    37     }
    38     printf("%lld", ans);
    39     return 0;
    40 }
    AC代码
  • 相关阅读:
    aspx页面,中文乱码解决方案
    使用JSP体验微信公众平台开发模式
    使用微信公众平台“编辑模式”的过程记录
    JAVA刷新网站IP访问量的技术探讨
    301. Remove Invalid Parentheses
    Dungeon Game
    刷题关键点总结-动态规划
    刷题关键点总结-单调栈、单调队列
    coin change
    常用vim命令
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/9585484.html
Copyright © 2020-2023  润新知