BZOJ 1096 [ZJOI2007]仓库建设 BZOJ 3437 小P的牧场 BZOJ 3156 防御准备 斜率优化dp

[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
",f[n]);
}

欢迎来原博客看看 >原文链接<

原文地址:https://www.cnblogs.com/Tobichi/p/9078908.html