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

    1. Watching Fireworks is Fun(CF372C)

     Decscription

    • 一个节日将在一个镇的主街道上举行。 街道被分为(n)段,从左到右编号为(1)(n),每个相邻部分之间的距离为(1)

    • 节日里在主街道有 (m) 个烟花要放,第(i(1le ile m))次烟花将在 (t_i) 时在 (a_i) 段燃放。 如果您在第 (i) 次发射时处于 (x(1le x le n)) ,您将获得幸福值 (b_i-|a_i-x|) (请注意,幸福价值可能是负值)

    • 您可以以单位时间间隔移动长度为 (d) 个长度单位,但禁止离开主要街道。 此外,在初始时刻(时间等于 (1) )你可以在街道的任意部分,并希望最大化从观看烟花获得的幸福总和。 找到最大的总幸福。

    • 请注意,两个或多个烟花可以同时发射

    Input

    • 第一行包含三个整数(n, m, d (1≤ n ≤150000; 1≤ m ≤300; 1≤ d ≤ n))

    • 接下来(m)行每行包含三个整数(a_i, b_i, t_i (1≤ a_i ≤ n; 1≤ b_i ≤10^9; 1≤ t_i ≤10^9))。第(i)行描述第(i)次烟花发射

    • 确保满足条件(t_i≤t_{i + 1}(1≤i<m))

    Output

    • 输出一个整数 —— 从观看所有烟花获得的最大幸福总和

    Sample Input

    样例输入1:
    50 3 1
    49 1 1
    26 1 4
    6 1 10
    
    样例输入2:
    10 2 1
    1 1000 4
    9 1000 4
    

    Sample Output

    样例输出1:
    -31
    
    样例输出2:
    1992
    
    • 分析

      • 如果 (i) 时位置确定,在 (x_i) ,则到下一个燃放时刻时最远能一定(h=(t_{i+1}-t_i)*d),则位置可能在$[x_i-h,x_i+h] $ 。

      • 所以该次燃放后可能获得的幸福总和由上一次位于([j−h,j+h])处的(2h+1)种情形得到。

      • 定义:(dp[i][j]),表示第 (i) 次烟花燃放时位于 (j) 时所能获得的最大的幸福总和。

      • 动态转移方程:(dp[i][j]=max(dp[i-1][k])+b[i]-|a[i]-j|,kin [j-h,j+h])

        • (i) 次燃放时处于 (j(1le jle n)),那第 (i-1) 次燃放时必须能到达 (j) ,所以 (j-hle k le j+h)
        • 当前状态至于上一行的某个区间的最值有关,我们很快就能联想起用单调队列进行优化。
        • 当前行状态至于上一行的状态相关,果断滚动数组压维。
        • 时间效率:(O(m*n))
      • Code

        #include <bits/stdc++.h>
        typedef long long LL;
        const int maxn=15e4+5;
        LL dp[2][maxn];
        void Solve(){
            int n,m,d;scanf("%d%d%d",&n,&m,&d);
            int pre_t=1,k=0;//pre_t 记录上一个烟花的时刻,k滚动数组标记,k当前行,!k上一行
            while(m--){
                int a,b,t;scanf("%d%d%d",&a,&b,&t);
                LL h=1LL*(t-pre_t)*d;//从上一个时刻到这个烟花燃放时刻最远能走多远
                h=std::min(h,LL(n));//h过大没什么意义,最大为n
                pre_t=t;//为下一个时刻做准备
                k=!k;//滚动数组标记
                std::deque <int> q;
                for(int i=1,j=1;i<=n;++i){//i枚举当前燃放时所处的位置,j表示上一个烟花时可能的为主    
                    for(;j<=i+h && j<=n;++j){//注意j在上面定义的,即当i改变位置时,j没有重新赋值
                        while(!q.empty() && dp[!k][q.back()]<=dp[!k][j])q.pop_back();
                        q.push_back(j);//当上一行j位置的dp值比队尾大时显然,队尾就没用了
                    }
                    while(!q.empty() && q.front()<i-h)q.pop_front();//保证左边范围
                    dp[k][i]=dp[!k][q.front()]+b-std::abs(a-i);
                }
            }
            LL ans=dp[k][1];
            for(int i=2;i<=n;++i)//看最后一个烟花时,你可能在1~n的任何一个位置
                ans=std::max(ans,dp[k][i]);
            printf("%lld
        ",ans);
        }
        int main(){
            Solve();
            return 0;
        }
        
  • 相关阅读:
    黄金矿工(LeetCode Medium难度)1129题 题解(DFS)
    String,StringBuffer,StringBuilder区别(笔记)
    ArrayList 与LinkedList 的区别及分别的优缺点
    每日温度(LeetCode Medium难度算法题)题解
    openCV从入门到放弃
    visualStudio 的一些常用使用操作总结
    angularjs和ajax的结合使用 (三)
    来手撸一个小小小小小"3D引擎"
    WPF的TextBox水印效果详解
    WPF使用总结
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13191368.html
Copyright © 2011-2022 走看看