[ZJOI2007]仓库建设

还是和这题一样

https://blog.csdn.net/qq_38944163/article/details/91369545


20’(66’)

dp方程写出来大概是这样的
s 1 [ i ] = ∑ P [ j ] , s 2 [ i ] = ∑ P [ j ] ∗ X [ j ] s1[i]=\sum P[j], s2[i]=\sum P[j]*X[j] s1[i]=P[j],s2[i]=P[j]X[j]
f [ i ] = M i n ( f [ j ] + X [ i ] ∗ ( s 1 [ i ] − s 1 [ j ] ) − ( s 2 [ i ] − s 2 [ j ] ) + C [ i ] ) f[i] = Min(f[j] + X[i] * (s1[i] - s1[j]) - (s2[i] - s2[j]) + C[i]) f[i]=Min(f[j]+X[i](s1[i]s1[j])(s2[i]s2[j])+C[i])

然而O(n^2)的暴力貌似艹到了66‘
https://www.luogu.org/recordnew/show/19752554
code:

#include<bits/stdc++.h>
#define int long long
#define N 1000005
using namespace std;
int n, X[N], P[N], C[N], s1[N], s2[N], f[N];
signed main(){
    scanf("%lld", &n);
    for(int i = 1; i <= n; i ++){
        scanf("%lld%lld%lld", &X[i], &P[i], &C[i]);
        s1[i] = s1[i - 1] + P[i];
        s2[i] = s2[i - 1] + X[i] * P[i];
    }
    memset(f, 0x3f, sizeof f);
    f[0] = 0;
    for(int i = 1; i <= n; i ++)
        for(int j = 0; j < i; j ++) 
            f[i] = min(f[i], f[j] + X[i] * (s1[i] - s1[j]) - (s2[i] - s2[j]) + C[i]);
    printf("%lld", f[n]);
    return 0;
}

100’

转移方程可以变成
f [ i ] = f [ j ] + X [ i ] ∗ s 1 [ i ] − s 1 [ j ] ∗ X [ i ] − s 2 [ i ] + s 2 [ j ] + C [ i ] f[i] = f[j] + X[i] * s1[i] - s1[j] * X[i] - s2[i] + s2[j] + C[i] f[i]=f[j]+X[i]s1[i]s1[j]X[i]s2[i]+s2[j]+C[i]
最终可以变成这样
s 1 [ j ] ∗ X [ i ] + f [ i ] − X [ i ] ∗ s 1 [ i ] + s 2 [ i ] − C [ i ] = f [ j ] + s 2 [ j ] s1[j] * X[i] + f[i] - X[i] * s1[i] + s2[i] - C[i] = f[j] + s2[j] s1[j]X[i]+f[i]X[i]s1[i]+s2[i]C[i]=f[j]+s2[j]

可以这么看

s 1 [ j ] ∗ X [ i ] s1[j] * X[i] s1[j]X[i] ----------------------------把 s 1 [ j ] s1[j] s1[j]看作 x x x, 即斜率 k k k X [ i ] X[i] X[i]
+
f [ i ] − X [ i ] ∗ s 1 [ i ] + s 2 [ i ] − C [ i ] f[i] - X[i] * s1[i] + s2[i] - C[i] f[i]X[i]s1[i]+s2[i]C[i] --------------------------------这个看作 b b b

=
f [ j ] + s 2 [ j ] f[j] + s2[j] f[j]+s2[j]--------------------------------这个看作 y y y
然后套路和之前的一样
code:

#include<bits/stdc++.h>
#define int long long
#define double long double
#define N 1000005
using namespace std;
int n, X[N], P[N], C[N], s1[N], s2[N], f[N], dp[N], q[N];
double x(int i) {return s1[i];}
double y(int i) {return dp[i] + s2[i];}
double Slope(int i, int j) {return (y(i) - y(j)) / (x(i) - x(j));}
signed main(){
	scanf("%lld", &n);
	for(int i = 1; i <= n; i ++){
		scanf("%lld%lld%lld", &X[i], &P[i], &C[i]);
		s1[i] = s1[i - 1] + P[i];
		s2[i] = s2[i - 1] + X[i] * P[i];
	}
	int l = 1, r = 1;
	 for(int i = 1; i <= n; i ++){
        while(l < r && Slope(q[l], q[l + 1]) < X[i]) l ++;
        int j = q[l]; 
        //dp[i] = y(j) - X[i] * x(j) - (- X[i] * s1[i] + s2[i] - C[i]);
        dp[i] = dp[j] + X[i] * (s1[i] - s1[j]) - (s2[i] - s2[j]) + C[i];//上面这两种都可以,因为j就是最优决策点
        while(l < r && Slope(q[r - 1], q[r]) > Slope(i, q[r - 1])) r --;
        q[++ r] = i;
    }
	printf("%lld", dp[n]);
	return 0;
}

emmmmm……

posted @ 2019-06-10 15:06  lahlah  阅读(27)  评论(0编辑  收藏  举报