• 斜率优化--P3195 [HNOI2008]玩具装箱


    斜率优化的基本形式

    对于这样形式的(dp)方程:(dp_i=Min/Max(a_i imes b_j+c_j+d_i)),其中(b)严格单调递增。

    该方程的关键点在于(a_i imes b_j)这一项,它既有(i)又有(j),于是单调队列优化不再适用,可以尝试使用斜率优化。

    代数理解

    因为感觉图像理解并不是很严谨,所以推一下式子,比如这道题 P3195 [HNOI2008]玩具装箱:

    转移方程:(f_i = min(f_j+{(sum_i-sum_j+i-j-1-L)}^2)) 既然是讲斜率优化,状态转移应该就不用说了把

    我们把这一系列的变量分类,把与(i)有关和与(j)有关的变量分开,(A = sum_i+i)(B = sum_j+j+L+1)

    那么原式子就转化为(f_i = f_j+{(A-B)}^2 = f_j+A^2+B^2-2AB) (因为每一个(i)只会由一个最优的(j)转移过来,所以我们可以先把(min)拿掉)

    对于两个(j)(1leq j_1 < j_2leq n),如果(f_{j_2})(f_{j_1})更优,那么:

    (f_{j_1}+A^2+{B_1}^2-2AB_1 > f_{j_2}+A^2+{B_2}^2-2AB_2),变形后可得:(frac{(f_{j_2} + {B_2}^2) - (f_{j_1}+{B_1}^2)}{B_2-B_1} < 2A_i)

    可以发现他们两两形式相同,那么我们就可以改写成(frac{Y_2-Y_1}{X_2-X_1} < k)

    我们发现当(j_1)(j_2)连成的直线斜率小于(k),选后面的点(j_2)更优,那么对答案产生贡献的就是第一个斜率大于(k)的前面的点(这好像只能画图理解了,我并不会说明呀)

    变形状态转移的方法

    (dp_i=Min/Max(a_i imes b_j+c_j+d_i)),其中(i imes j)的一项里,含(i)的是斜率,含(j)的是(x),剩下右边含(j)的是(y),其余的是(b)

    code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a;
    }
    const int maxn = 5e4+10;
    int n,l;
    double sum[maxn],A[maxn],B[maxn],c[maxn];
    double dp[maxn],q[maxn];
    double X(int x){return B[x];}
    double Y(int x){return dp[x]+B[x]*B[x];}
    double solve(int a,int b){return (Y(a)-Y(b))/(X(a)-X(b));}
    int main(){
    	n = read(),l = read();
    	for (int i = 1;i <= n;i++) scanf("%lf",&c[i]),sum[i] = sum[i-1] + c[i];
    	for (int i = 1;i <= n;i++) A[i] = sum[i]+i,B[i] = sum[i]+i+l+1;
    	B[0] = l+1;
    	int head = 1,tail = 1;
    	for (int i = 1;i <= n;i++){
    		while (head < tail&&solve(q[head],q[head+1]) < 2*A[i]) head++;
    		int j = q[head];dp[i] = dp[j]+(A[i]-B[j])*(A[i]-B[j]);
    		while(head < tail&&solve(i,q[tail-1]) < solve(q[tail-1],q[tail])) tail--;
    		q[++tail]=i;
    	}
    	printf("%lld
    ",(long long)dp[n]);
    	return 0;
    }
    
  • 相关阅读:
    自学Python编程的第二天----------来自苦逼的转行人
    自学Python编程的第一天----------来自苦逼的转行人
    A-B 高精度
    A+B 高精度
    [NOI2002]银河英雄传说
    口袋的天空
    修复公路(并查集)
    并查集
    Surjectivity is stable under base change
    为什么Fourier分析?
  • 原文地址:https://www.cnblogs.com/little-uu/p/13999098.html
Copyright © 2020-2023  润新知