zoukankan      html  css  js  c++  java
  • [笔记] [题解]斜率优化$DP$&洛谷P3195玩具装箱

    [笔记] [题解]斜率优化(DP)&洛谷P3195玩具装箱

    可能加载的有点慢,在预览的时候可能公式显示不了,点进去看就行了QvQ

    原题链

    斜率优化讲解

    对于洛谷上的这道题,我们设(sum[k] = sum_{i=1}^kC[i]+1)(可以把S数组视为(C)的前缀和),用(dp[i])表示装好前(i)个玩具的最小费用,不是长度,那么我们可以得到转移方程:

    [dp[i]=min_{0leq j<i}(dp[j]+(sum_{k=j+1}^{i}C_k+i-j-1-L)^2)\ dp[i]=min(dp[j]+(sum[i]-sum[j]-1+L)^2) \ 令f[i]=sum[i]+i,可继续化简得: \ dp[i]=min(dp[j]+(f[i]-f[j]-1-L)^2) ]

    此时暴力进行(DP)(O(n^2))的,仍然要优化.

    对于每一个(dp[i])都是由一个(j)推到而来的,并且这个(j)是对于当前的(i)的最优决策.现在假设有(j_1,j_2(1{leq}j_1{<}j_2{<}i)),并且决策(j_2)优于(j_1),那么就有

    [dp[j_1]+(f[i]-f[j_1]-1-L)^2 geq dp[j_2]+(f[i]-f[j_2]-1-L)^2\ 拆括号得\ dp[j_1]+f[i]^2-2f[i](f[j_1]+1+L)+(f[j_1]+L+1)^2geq dp[j_2]+f[i]^2-2f[i](f[j_2]+1+L)+(f[j_2]+L+1)^2\ 化简可得:\ 2f[i](f[j_2]+1+L)-2f[i](f[j_1]+1+L) geq dp[j_2]+(f[j_2]+1+L)^2-(dp[j_1]+f[j_1]+1+L)^2\ 即\ 2f[i] geq frac{dp[j_2]+(f[j_2]+1+L)^2-(dp[j_1]+(f[j_1]+1+L)^2)}{f[j_2]-f[j_1]}\ 令g[i]=(f[i]+L+1)^2,可得: 2f[i] geq frac{dp[j_2]+g[j_2]-(dp[j_1]+g[j_1])}{f[j_2]-f[j_1]} ]

    那么也就是说如果有(j_1,j_2)满足这两个式子,那么(j_2)一定比(j_1)要更优.

    那么为什么要叫斜率优化呢?其实我们观察最终得到的式子可以吧(dp[i]+g[i])看做纵坐标,(f[i])看做横坐标,那么这个式子其实就相当于(k=frac{{Delta}y}{{Delta}x}),也就是一个一次函数的斜率表达式,当这个斜率(k leq 2f[i])时则(j_2)优于(j_1).

    根据上面推出来的关系我们就可以用最优的决策来更新答案了,代码就是上面公式的翻译,加上一个单调队列

    代码

    #include <bits/stdc++.h>
    using namespace std;
    long long n,l;
    long long sum[500010],f[500010],head,tail,q[50010],dp[500010],g[500010];
    double slope(int x,int y){
    	return (double)(dp[y] + g[y] - dp[x] - g[x]) / (f[y] - f[x]);
    }
    int main(){
    	scanf("%lld%lld",&n,&l);
    	for(int i = 1;i <= n;i++){
    		scanf("%lld",&sum[i]);
    		sum[i] += sum[i - 1];
    		f[i] = sum[i] + i;
    		g[i] = (f[i] + l + 1) * (f[i] + l + 1);
    	}
    	g[0] = (l + 1) * (l + 1);
    	for(int i = 1;i <= n;i++){
    		while(head < tail && slope(q[head],q[head + 1]) <= 2 * f[i])head++;
    		dp[i] = dp[q[head]] + (f[i] - f[q[head]] - l - 1) * (f[i] - f[q[head]] - l - 1);
    		while(head < tail && slope(q[tail],i) < slope(q[tail - 1],q[tail]))tail--;
    		q[++tail] = i;
    	}
    	printf("%lld
    ",dp[n]);
    	return 0;
    }
    
  • 相关阅读:
    体验一下:AndroidX
    Android研发技术的进阶之路
    App 冷启动与热启动及启动白屏优化
    Android Q 正式命名为 Android 10
    Android开发学习路线的七个阶段和步骤
    安卓旅途之——开发数独(一)
    项目总结
    小组互评与自评
    典型用户与场景
    第二个Sprint计划
  • 原文地址:https://www.cnblogs.com/czy--blog/p/13954497.html
Copyright © 2011-2022 走看看