[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……