[ZJOI2007]仓库建设 >原题链接<
小P的牧场 >原题链接<
防御准备 >原题链接<
由于是三题,就不放题面了
思路 :
BZOJ1096:本题Dp的方程比较好推导,我们设两个sum数组分别对货物量进行前缀求和、sum1对前i-1个仓库的货物都运到i的代价进行求和
设F[i]为在i点建仓库的总最小花费。
那么Dp方程显然为F[i]=min{ f[j] + sum1[i] - sum1[j] - sum[j] * ( x[i] - x[j] ) + c[i] } 考虑斜率优化 。 对本式进行化简得
F[i]-c[i] - sum1[i] = F[j] - sum1[j] - sum[j] * x[j] + s[j] * x[i] ;
我们设
B(j) = F[j] + x[j] * s[j] -sum1[j]
K(j)= -sum[j];
Y (i,j) = K(j)* x[i] + B(j) = F[i] - c[i] - sum1[i]
故F[i] = Y(i,j) + sum1[i] + c[i]
考虑单调性 K(j) 单调递减 x[i]单调递增 若队尾和I构成的斜率斜率小于队尾二号和i构成的斜率,则弹出队尾;
考虑队首元素时,若Y(队首) >= Y(队首2号元素) 则弹出队首 。
而BZOJ 3437 只是把x[i]变成了i,其他的没有变化
而BZOJ 3156 只是在上题的基础上把sum[i]变成i,其他的没有变化。
附上1096的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1200000;
#define int long long
#define ll long long
#define K(i) (-s[i])
#define B(i) (f[i]+x[i]*s[i]-s1[i])
#define Y(i, j) (K(j)*x[i]+B(j))
int x[N], p[N], c[N], s[N], s1[N], f[N];
int q[N], l, r;
bool cmp(int i,int j,int k)
{
ll aslhkdfljkashdfkljsahdkljfhasdkjf=(K(i)-K(k))*(B(j)-B(i));
ll y=(K(i)-K(j))*(B(k)-B(i));
return aslhkdfljkashdfkljsahdkljfhasdkjf>=y;
}
#undef int
int main() {
int n, i;
scanf("%d",&n);
for(i=1;i<=n;i++) {
scanf("%lld%lld%lld",&x[i],&p[i],&c[i]);
s[i]=s[i-1]+p[i];
s1[i]=s1[i-1]+s[i-1]*(x[i]-x[i-1]);
}
for(i=1;i<=n;i++) {
while(l<r&&Y(i,q[l])>=Y(i,q[l+1])) l++;
f[i]=Y(i,q[l])+s1[i]+c[i];
while(l<r&&cmp(i,q[r-1],q[r]))r--;
q[++r]=i;
}
printf("%lld\n",f[n]);
}
欢迎来原博客看看 >原文链接<