• Luogu3195 [HNOI2008]玩具装箱TOY (方程变形 + 斜率优化 )


    题意:

      给出一个序列 {a[i]} 把其分成若干个区间,每个区间的价值为 W = (− i + ∑ak(i<=k<=j) - L),求所有分割方案中价值之和的最小值。

    细节:

      仔细看数据范围:1 <= N <= 50000 ,1 <= C[i] <= 10^7,所以不忘记开Long Long / Int64,咳咳我很关心 Pascal 选手。

    分析:

      显然一题划分区间求最值的题目,所以可以用动态规划解决,联想一下状态:f[i] 表示以 i 为结尾且以 i 为断点的最小价值和。

      考虑到 i 是断点的问题所以对于后面的状态,新的一段区间是不包括 i 的,所以我们可以开始转移了:f[i] = min { f[j] + (sum[i] - sum[j] + i - (j + 1) - L)2 }

      得到了一个 1D/1D 的动规方程,对于这一类式子我们一般考虑优化转移,显然状态无法进行优化,不然思想转变成了贪心,显然局部最有不满足全局最有,我们可以尝试是否存在在转移时的无用状态,所谓无用状态是一些不优的状态,我们显然可以选择最有的状态进行转移,其满足最有字结构的性质。

      不妨令 j1 < j2 < i,且 j1 的转移不必 j2 优,从中我们可以发现不需要去求解 j1 直接从 j2 进行转移不会影响答案,且能够节省时间。

      所以我们可以得到式子 f[j2] + (sum[i] - sum[j2] + i - (j2 + 1) - L)2 <= f[j1] + (sum[i] - sum[j1] + i - (j1 + 1) - L)2,由于式子过于复杂我们考虑换元。

      不妨再令 a[i] = sum[i] - L + i - 1,b[i] = sum[i] + i

      所以式子转换成:f[j2] + ( a[i] - b[j2] )<= f[j1] + ( a[i] - b[j1] )2

      最后可得:f[j2]+ b[j2]-f[j1]-b[j1]2 <= 2 × a[i] ×( b[j2] - b[j1] ) 所以此时我们可以考虑斜率优化具体的分析请详见一下本人博客

    代码:

    本人压行怪物请见谅:
    
    #include<bits/stdc++.h>
    #define MAXN 50010
    #define LL long long
    using namespace std;
    
    LL f[MAXN], sum[MAXN], a[MAXN], b[MAXN];
    int n, L, que[MAXN];
    
    int main(){
        scanf("%d%d", &n, &L);
        for (int i=1; i<=n; i++){
            LL x;
            scanf("%lld", &x);
            sum[i]=sum[i-1]+x;
        }
        for (int i=1; i<=n; i++) a[i]=sum[i]+i-1-L, b[i]=sum[i]+i;
        int head=1, tail=1;
        for (int i=1; i<=n; i++){
            while (head<tail && 2*a[i]*(b[que[head+1]]-b[que[head]])>=f[que[head+1]]-f[que[head]]+b[que[head+1]]*b[que[head+1]]-b[que[head]]*b[que[head]]) ++head;
            f[i]=f[que[head]]+(a[i]-b[que[head]])*(a[i]-b[que[head]]);
            while (head<tail && (f[que[tail]]+b[que[tail]]*b[que[tail]]-f[que[tail-1]]-b[que[tail-1]]*b[que[tail-1]])*(b[i]-b[que[tail]])>=(f[i]+b[i]*b[i]-f[que[tail]]-b[que[tail]]*b[que[tail]])*(b[que[tail]]-b[que[tail-1]])) --tail;
            que[++tail]=i;
        }
        printf("%lld
    ", f[n]);
        return 0;
    }
  • 相关阅读:
    数据库事务的四个隔离级别
    synchronized与Lock的区别
    线程池的注意事项
    守护线程与非守护线程
    wait与sleep的区别
    String,StringBuffer,StringBuilder
    2019牛客暑期多校训练营 第二场
    2019牛客暑期多校训练营 第一场
    Codeforces Round #568 (div. 2)
    Codeforces Round #570 (Div. 3)
  • 原文地址:https://www.cnblogs.com/xiannvzuimei/p/9987631.html
Copyright © 2020-2023  润新知