• poj 3017 Cut the Sequence(单调队列优化 )


    题目链接:http://poj.org/problem?id=3017

    题意:给你一个长度为n的数列,要求把这个数列划分为任意块,每块的元素和小于m,使得所有块的最大值的和最小 

    分析:这题很快就能想到一个DP方程 f[ i ]=min{ f[ j ] +max{ a[ k ] }}( b[ i ]<j<i,j<k<=i)     b[ i ]到 i的和大于m 

    这个方程的复杂度是O(n^2),明显要超时的(怎么discuss都说数据弱呢= =) 

    然后是优化了,首先当然是要优化一个最大值的队列,使得这个队列的队首元素的到当前位置的和不超过m, 

    这样一个可行解就是,f[ i ]=f[b[ i ]-1]+a[ q[ l ]](即队首元素的值), 

    这并不是最优解,所以还要找到队列中的最优解,一个可能的最优解只能是这样的 

     f[ q[ j ] ]+ a[ q[j +1 ]],也就是 a[ j ] 要大于后面的数, 

     很显然,如果a[ j ]小于后面的数,那么我们就可以将 a[ j ] 划分到后面去,而取得更优解 

     这里涉及的这个找最优解问题;

    AC代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 using namespace std;
     6 typedef long long LL;
     7 const int N = 100020;
     8 LL num[N];
     9 LL sum[N];
    10 LL f[N];
    11 int q[N];
    12 int main() {
    13     int n, i, j, st, ed, p;
    14     LL m;
    15     while(~scanf("%d%I64d", &n, &m)) {
    16         memset(f, -1, sizeof(f));
    17         st = 0, ed = -1;
    18         p = 1;
    19         sum[0] = 0;
    20         f[0] = 0;
    21         for(i = 1; i <= n; ++i) {
    22             scanf("%I64d", num + i);
    23             sum[i] = sum[i-1] + num[i];// 统计前n项的和
    24             if(st > ed) {
    25                 st = 0, ed = -1;
    26                 q[++ed] = i;
    27             }
    28             while(st <= ed && num[i] >= num[q[ed]])   --ed;//单调队列优化
    29             q[++ed] = i;
    30             while(sum[i] - sum[p-1] > m)    ++p;
    31             while(st <= ed && p > q[st])    st++;//单调队列里面保存的数已经被删除,则底部++;
    32             if(st > ed) continue;  //当前队列为空了,直接返回
    33             if(f[p-1] != -1) //如果当前p位,有数;
    34                 f[i] = f[p-1] + num[q[st]];
    35             for(j = st + 1; j <= ed; ++j) {
    36                 if(f[q[j]-1] != -1)
    37                     f[i] = min(f[i], f[q[j-1]] + num[q[j]]);
    38             }
    39         }
    40         printf("%I64d
    ",f[n]);
    41     }
    42     return 0;
    43 }
  • 相关阅读:
    为什么我要学习qt quick
    geometory Intersect
    删除kubernetes节点的正确姿势
    乞丐版docker私有仓库搭建
    kubernetes集群中由于某些原因导致etcd节点没有删干净,需要手动清理etcd节点
    k8s coredns设置上游name server
    虚拟机架设koolshare软路由
    文件类型特征码
    深入字节码 -- 计算方法执行时间
    启迪思维:二叉树
  • 原文地址:https://www.cnblogs.com/lovychen/p/4458351.html
Copyright © 2020-2023  润新知