zoukankan      html  css  js  c++  java
  • CF372C Watching Fireworks is Fun

    传送门

    一道有趣的DP

    题目大意

    城镇中有 $n$ 个位置,有 $m$ 个烟花要放。第 $i$ 个烟花放出的时间记为 $t_{i}$ ,放出的位置记为 $a_{i}$ 。如果烟花放出的时候,你处在位置 $x$,那么你将收获 $b_{i}- left | a_{i}-x ight |$ 点快乐值。

    初始你可在任意位置,你每个单位时间可以移动不大于$d$个单位距离。现在你需要最大化你能获得的快乐值。

    思路:DP+单调队列+滚动数组

    有一个显然的动态转移方程:

    $$
    f_{i,j}=max left (f_{i,j},f_{i-1,k}+b_{i}- left |a_{i}-j ight | ight )
    $$

    $f_{i,j}$ 表示在位置 $j$ 放第 $i$ 个烟花获得的最大值。

    则 $ans=max_{i=1}^{n}f_{m, i}$。

    观察方程,可以看出 $b_{i}$ 可以提出来,而 $- left |a_{i}-j ight |$ 的值在计算的过程中也是确定的,也可提出来。

    最后的式子长这个样子

    $$
    f_{i,j}=min left (f_{i,j},f_{i-1,k} ight )
    //
    ans=sum_{i=1}{m}b_{i}-min_{i=1}{n}f_{m, i}
    $$

    感觉可以,一看复杂度 $O left ( n^{2}m ight )$,T 到飞起。

    从上式中,可以看出 $k$ 的范围是

    $$
    j- left ( t_{i}-t_{i-1} ight ) *d leq k leq j+ left ( t_{i}-t_{i-1} ight ) *d
    $$

    如何维护 $k$ 的值?很明显,用单调队列维护,使得其能在均摊 $0 left (1 ight )$ 的时间复杂度内计算出 $min left (f_{i,j},f_{i-1,k} ight )$。

    于是复杂度从 $O left ( n^{2}m ight )$ 降到了 $O left ( nm ight )$。

    一看范围,150000。。。直接爆炸。

    仔细观察,发现可以用滚动数组优化空间,能过。

    代码

    #include <iostream>
    
    #define RI register int
    typedef long long ll;
    const int N = 150001;
    
    using namespace std;
    
    template <class T>
    inline void read(T &x) {
        T f = 1; x = 0; char c = getchar();
        while(c > '9' || c < '0') {
            if(c == '-')
                f = -f;
            c = getchar();
        }
        while(c >= '0' && c <= '9') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        x *= f;
    }
    
    int n, m, d, t[2];
    ll f[2][N], ans = 1e18 + 7, sum;
    int l, r, q[N];
    int p;
    
    inline int abs(int x) {
        return x > 0 ? x : -x;
    }
    
    inline ll min(ll x, ll y) {
        return x > y ? y : x;
    }
    
    int main() {
        read(n), read(m), read(d);
        for(RI i = 1; i <= m; i++) {
            int a, b;
            read(a), read(b), read(t[p ^ 1]);
            sum += b;
            ll len = ll(t[p ^ 1] - t[p]) * d;
            l = 1, r = 0;
            for(RI j = 1; j <= n; j++) {
                while(l <= r && q[l] < j - len)
                    l++;
                while(l <= r && f[p][q[r]] > f[p][j])
                    r--;
                q[++r] = j;
                f[p ^ 1][j] = f[p][q[l]] + abs(a - j);
            }
            l = 1, r = 0;
            for(RI j = n; j >= 1; j--) {
                while(l <= r && q[l] > j + len)
                    l++;
                while(l <= r && f[p][q[r]] > f[p][j])
                    r--;
                q[++r] = j;
                f[p ^ 1][j] = min(f[p][q[l]] + abs(a - j), f[p ^ 1][j]);
            }
            p ^= 1;
        }
        for(RI i = 1; i <= n; i++)
            ans = min(ans, f[p][i]);
        printf("%lld
    ", sum - ans);
        return 0;
    }
    
  • 相关阅读:
    numpy计算路线距离
    WebApi安全性 使用TOKEN+签名验证
    从SQL查询分析器中读取EXCEL中的内容
    Autofac应用总结
    Visual Studio提示“无法启动IIS Express Web服务器”的解决方法
    架构 : 三层架构、MVC、MVP、MVVM
    Asp.Net MVC :路由器
    myeclipse10安装egit和使用
    myeclipse10.7安装git插件
    SQLite之C#连接SQLite
  • 原文地址:https://www.cnblogs.com/ASTiKi/p/12285911.html
Copyright © 2011-2022 走看看