• BZOJ 1096 ZJOI2007 仓库设计 斜率优化dp


       太高兴了,这是我第一次自己独立思考的斜率优化dp,从头到尾都是自己想的。(相信自己,能行的,不过也做了40分钟了)。 这道题目还好吧! 看到之后第一反应是想设从工厂0运到工厂i 总共需要 tot[i] 的费用, 用 p[i] 表示从山顶到工厂 i 总共的产品数, 再用 x[i] 表示从工厂0到工厂 i 的距离, 那么状态转移方程就是 f[i] = min{f[j] + tot[i] - tot[j] - p[j] * (x[i] - x[j] ) + c[i] } ,很明显由于数据有 n <= 1000000 不能 n ^ 2 的朴素算法, 要进行优化。  先看一下状态转移方程, 除了 f[j] 不定之外, 其他的在数据给出时都已确定(换句话说,满足无后效性,只要保证之前处理f[i]时,f[i]是最小就好),可以考虑斜率优化。

    那么设 j < k , 目前正在处理 f[i]; 如果 j 比 k 差的话, 那么 f[j] + tot[i] - tot[j] - p[j] * (x[i] - x[j] ) >= f[k] + tot[i] - tot[k] - p[k] * (x[i] - x[k]) 

    移项化简得当 f[j] - f[k] - tot[j] + tot[k] + p[j] * x[j] - p[k] * x[k] >= x[i] * (p[j] - p[k]) 时 j 比 k 差。

    又因为求的是最小值所以要维护一个下凸函数。加油,努力。(1700毫秒)

     1 #include<cstdio>
     2 #include<iostream>
     3 #define rep(i,j,k) for(int i = j; i <= k; i++)
     4 #define maxn 1000005
     5 #define ll long long
     6 using namespace std;
     7 
     8 int read()
     9 {
    10     int s = 0, t = 1; char c = getchar();
    11     while( !isdigit(c) ){
    12         if( c == '-' )t = -1; c = getchar();
    13     }
    14     while( isdigit(c) ){
    15         s = s * 10 + c -'0'; c = getchar();
    16     }
    17     return s * t;
    18 }
    19 
    20 ll tot[maxn] = {0}, f[maxn] = {0}, c[maxn] = {0}, p[maxn] = {0}, x[maxn] = {0};
    21 int q[maxn] = {0};
    22 
    23 ll S(int k,int j)
    24 {
    25     return f[j] - f[k] + p[j] * x[j] - p[k] * x[k] + tot[k] - tot[j];
    26 }
    27 
    28 ll G(int k,int j)
    29 {
    30     return p[j] - p[k];
    31 }
    32 
    33 int main()
    34 {
    35    int n = read();
    36    rep(i,1,n){
    37          x[i] = read(), p[i] = read(), c[i] = read();  p[i] += p[i-1];
    38    }
    39    rep(i,1,n){
    40         tot[i] = p[i-1] * (x[i]-x[i-1]) + tot[i-1];
    41    }
    42    int l = 0, r = 0; q[r] = 0;
    43    rep(i,1,n){
    44          while( l < r && S(q[l+1],q[l]) >= G(q[l+1],q[l]) * x[i] ) l++;
    45          int j = q[l];
    46          f[i] = f[j] + tot[i] - tot[j] + c[i] - p[j] * (x[i]-x[j]);
    47          while( l < r && S(q[r],q[r-1]) * G(i, q[r]) >= S(i,q[r]) * G(q[r],q[r-1]) ) r--;
    48       q[++r] = i;
    49    }
    50    cout<<f[n]<<endl;
    51    return 0;
    52 }
  • 相关阅读:
    leetcode131分割回文串
    leetcode315 计算右侧小于当前元素的个数
    Tensorflow写代码流程&反向传播
    vue脚手架的搭建
    Vue 脱坑记
    简历中的工作经历要怎么写?
    如何制作高水平简历?
    window.location.hash的知识点
    前端面试题小集
    前端面试题
  • 原文地址:https://www.cnblogs.com/83131yyl/p/5103544.html
Copyright © 2020-2023  润新知