zoukankan      html  css  js  c++  java
  • 洛谷P6040 「ACOI2020」课后期末考试滑溜滑溜补习班 题解 单调队列优化DP

    题目链接:https://www.luogu.com.cn/problem/P6040

    解题思路:

    设状态 (f[i]) 表示老师走到第 (i) 个人的最小花费,则:

    [f[i] = min_{j in [i-x, i-1]}(f[j] + (i-j-1) imes k + d) ]

    暴力的方案是 (O(n cdot x)) 时间复杂度,必然超时。

    所以考虑单调队列优化,维护一个单调递增的单调队列。

    比较的规则是,如果队列当中存在两个坐标 (j1, j2)(j1 lt j2),则对于任意一个 (gt j1,j2)(i) 来说:

    • (j1)(i) 所需要的花费是 ((i-1-j1) cdot k + d)
    • (j2)(i) 所需要的花费是 ((i-1-j2) cdot k + d)

    而两者的花费只差是 ((j2-j1) cdot k)

    也就是说,既然队列是单调递增的,则对于 (j1 lt j2) 来说,必然存在

    [f[j1] + (j2-j1) imes k lt f[j2] ]

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 10000010;
    typedef long long ll;
    int n, k, d, x, tp, a[maxn], Seed;
    ll f[maxn];
    deque<int> que;
    inline int rnd () {
    	static const int MOD = 1e9;
    	return Seed = ( 1LL * Seed * 0x66CCFF % MOD + 20120712 ) % MOD;
    }
    int main() {
        scanf("%d%d%d%d%d", &n, &k, &d, &x, &tp);
        if (tp == 0) for (int i = 1; i <= n; i ++) scanf("%d", a+i);
        else {
            scanf("%d", &Seed);
            for (int i = 1; i <= n; i ++) a[i] = rnd();
        }
        f[1] = a[1];
        for (int i = 2; i <= n; i ++) {
            while (!que.empty()) {
                int j = que.back();
                if (f[j] + (ll)(i-1-j) * d >= f[i-1]) que.pop_back();
                else break;
            }
            que.push_back(i-1);
            if (que.front() < i-x) que.pop_front();
            f[i] = f[que.front()] + a[i] + k + (ll)(i - que.front() - 1) * d;
        }
        printf("%lld
    ", f[n]);
        return 0;
    }
    
  • 相关阅读:
    jfinal使用配置文件注意事情
    在项目中集成jetty server
    JFinal快速上手及注意事项
    表单处理的方案与注意事项(servlet)
    java四大会话技术
    servlet过滤器简化版
    python 生成器
    python 深复制和浅复制
    python 获取路径
    python selenium定位总结(转)
  • 原文地址:https://www.cnblogs.com/quanjun/p/12297376.html
Copyright © 2011-2022 走看看