• 【ZJOI 2007】仓库建设


    (Solution) 1

    这道题不算很难,这里我提供两种做法。

    设 dp[i] 为在 i 位上设置仓库,前面工厂都解决了的最小花费。首先我们可以列出 DP 式:

    [dp[i]=min(dp[j]+sigma(p[k]*(x[i]-x[k])))+c[i] ]

    [dp[i]=min(dp[j]+x[i]*sigma(p[k])-sigma(p[k]*x[k]))+c[i] ]

    我们定义 pre 数组为 p 数组的前缀和,s 数组为 (p[i]*x[i]) 的前缀和。用这两个数组乱搞就可以用斜率优化了。

    (Code) 1

    贴一下代码。

    #include <cstdio>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    const int N = 1e6 + 5;
    
    int n, q[N], head, tail;
    ll c[N], x[N], pre[N], dp[N], s[N];
    
    int read() {
        int x = 0, f = 1; char s;
        while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    }
    
    double slope(const int j1, const int j2) {
        return 1.0 * (dp[j2] + s[j2] - dp[j1] - s[j1]) / (pre[j2] - pre[j1]);
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; ++ i) {
            x[i] = read(), pre[i] = read(), c[i] = read();
            s[i] = s[i - 1] + x[i] * pre[i]; pre[i] += pre[i - 1];
        }
        for(int i = 1; i <= n; ++ i) {
            while(head < tail && slope(q[head], q[head + 1]) < x[i]) ++ head;
            int j = q[head];
            dp[i] = dp[j] + x[i] * (pre[i] - pre[j]) - (s[i] - s[j]) + c[i];
            while(head < tail && slope(q[tail], i) < slope(q[tail - 1], q[tail])) -- tail;
            q[++ tail] = i;
        }
        ll ans = dp[n];
        printf("%lld
    ", ans);
        return 0;
    }
    

    这里说一下一个疑惑。我们 dp[n] 的定义是保证 n 一定会是仓库的最小值。但是,题目并不保证工厂 n 的材料不为 0。也就是说,我们有可能选取之前的 dp 值,保证那个坐标的后面工厂都没有材料(也就不需要设置仓库了)。

    我是这样写的:

        ll ans = dp[n];
        for(int i = n; i >= 1; -- i) {
            if(pre[i] - pre[i - 1]) break;
            ans = min(ans, (long long) dp[i - 1]);
        }
        printf("%lld
    ", ans);
    

    HYSBZ 交上去是错的?好懵???(我怀疑是数据有锅或者是我想错了

    (Solution) 2

    这是我自己的方法, Luogu 可以过,只是 HYSBZ 过不去 QwQ。(应该是爆 long long 了,如果不是请大佬在评论区指教)

    dp 数组,pre 数组定义同上。这里的 s 数组有点不一样,表示前面所有工厂的材料都转移到 i 工厂的花费。则可以转化为:

    [dp[i]=min(dp[j]+s[i]-pre[j]*(x[i]-x[j])-s[j])+c[i] ]

    其中 (s[i]-pre[j]*(x[i]-x[j])-s[j]) 是将之前的 sigma 感性理解:i 与区间 ([j+1,i]) 的数匹配,每个地方向 i 的花费。我们首先 (s[i]-s[j]),剩下的就是 [1,j] 区间到 i 的花费要减去,而 (pre[j]*(x[i]-x[j])) 正是区间的成品数量乘上路程。

    我们设 (f[i]=s[i])(g[i]=pre[i]*x[i]-s[i]),然后乱搞出斜率优化?

    (Code) 2

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int n, q[N], head, tail;
    double c[N], x[N], pre[N], g[N], dp[N], s[N];
    
    int read() {
        int x = 0, f = 1; char s;
        while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    }
    
    double slope(const int j1, const int j2) {
        return (dp[j2] + g[j2] - dp[j1] - g[j1]) / (pre[j2] - pre[j1]);
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; ++ i) {
            x[i] = read(), pre[i] = read(), c[i] = read();
            pre[i] += pre[i - 1]; s[i] = s[i - 1] + 1.0 * (x[i] - x[i - 1]) * pre[i - 1];
            g[i] = pre[i] * x[i] - s[i];
        }
        for(int i = 1; i <= n; ++ i) {
            while(head < tail && slope(q[head], q[head + 1]) < x[i]) ++ head;
            dp[i] = dp[q[head]] + s[i] - pre[q[head]] * (x[i] - x[q[head]]) - s[q[head]] + c[i];
            while(head < tail && slope(q[tail], i) < slope(q[tail - 1], q[tail])) -- tail;
            q[++ tail] = i;
        }
        long long ans = dp[n];
        for(int i = n; i >= 1; -- i) {
            if(pre[i] - pre[i - 1]) break;
            ans = min(ans, (long long) dp[i - 1]);
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    如果有错误,请大佬在评论区留言哟!

  • 相关阅读:
    spring boot 启动报错(spring-boot-devtools热部署后):The elements [spring.resources.cache-period] were left unbound. Update your application's configuration
    一分钟搞定:spring boot 热部署 (基于Idea)
    如何将新项目添加到github仓库中?只需简单几步~即可实现
    spring boot 日志文件配置(logback-spring.xml)亲测可用!
    java后台读取/解析 excel表格
    String字符串存入数据库中超出最大长度(oracle varchar2 4000)?应合理分条存储(java实现-工具/方法)
    笔试题-sql语句
    总结--看帖收“货”
    Oracle-1
    蓝桥杯- 基础练习: 字母图形
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12557573.html
Copyright © 2020-2023  润新知