zoukankan      html  css  js  c++  java
  • CodeForces 372C--Watching Fireworks is Fun(单调队列优化DP)

    题目链接:https://codeforces.com/problemset/problem/372/C

    题目大意:有$n$个路段,$m$次放烟花,第$i$个烟花在第$t_i$时间在第$a_i$个路段燃放,可获得的价值为$b_i$,如果第$i$个烟花燃放的时候你在位置$x$那么,你将会获得$b_i-|a_i-x|$的价值,你每个单位时间可以移动$d$的长度,初始位置可以随意,问你最后能获得的最大价值是多少

    Examples

    Input
    50 3 1
    49 1 1
    26 1 4
    6 1 10
    Output
    -31
    Input
    10 2 1
    1 1000 4
    9 1000 4
    Output
    1992

    直接暴力DP的话应该很容易想到,定义DP状态为$dp[i][j]$表示第$i$个烟花燃放的时候在第$j$位置能够得到的最大价值,那么转移方程也很好写:$dp[i][j]=max(dp[i][j],dp[i-1][k]+fire[i].b-abs(fire[i].a-j))(kepsilon [j-h,j+h])$,那么第一维由于只用到了上一个状态,那么可以直接复制一下上一个状态就好了,暴力DP代码如下:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    typedef long long ll;
    const int mac=2e5+10;
    const ll inf=1e18+10;
    
    struct node
    {
        int a;
        ll b,t;
    }fire[mac];
    int q[mac];
    ll dp[mac],f[mac];
    
    int main(int argc, char const *argv[])
    {
        //freopen("in.txt","r",stdin);
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int n,m,d;
        cin>>n>>m>>d;
        for (int i=1; i<=m; i++){
            int a,b,t;
            cin>>a>>b>>t;
            fire[i]=node{a,b,t};
        }
        int head=1,tail=0;
        ll ans=-inf;
        fire[0]=node{0,0,fire[1].t};
        for (int i=1; i<=m; i++){//枚举烟花
            memcpy(f,dp,sizeof dp);
            for (int j=1; j<=n; j++){
                ll h=(fire[i].t-fire[i-1].t)*d;
                dp[j]+=fire[i].b-abs(fire[i].a-j);
                for (int k=max(1LL,j-h); k<=min((ll)n,j+h); k++){
                    dp[j]=max(dp[j],f[k]+fire[i].b-abs(fire[i].a-j));
                }
                if (i==m) ans=max(ans,dp[j]);
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    实际上我们只需要维护一下$f[k]$的在$j-h,j+h$的最大值就行了,那么我们可以想到单调队列,维护一个递减序列,我们先直接将整个递减序列构造出来,然后再对每个$j$只需要判断$j-h$是否大于q[head],这样就可以保证了区间的合法。

    以下是AC代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    typedef long long ll;
    const int mac=2e5+10;
    const ll inf=1e18+10;
    
    struct node
    {
        int a;
        ll b,t;
    }fire[mac];
    int q[mac];
    ll dp[mac],f[mac];
    
    int main(int argc, char const *argv[])
    {
        //freopen("in.txt","r",stdin);
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int n,m,d;
        cin>>n>>m>>d;
        for (int i=1; i<=m; i++){
            int a,b,t;
            cin>>a>>b>>t;
            fire[i]=node{a,b,t};
        }
        ll ans=-inf;
        for (int i=1; i<=m; i++){//枚举烟花
            memcpy(f,dp,sizeof dp);
            if (fire[i].t==fire[1].t){
                for (int j=1; j<=n; j++)
                    dp[j]=f[j]+fire[i].b-abs(fire[i].a-j);
                continue;
            }
            int head=1,tail=0,k=1;
            ll h=(fire[i].t-fire[i-1].t)*d;
            for (int j=1; j<=n; j++){
                while (k<=min((ll)n,j+h)){
                    while (head<=tail && f[k]>=f[q[tail]]) tail--;
                    q[++tail]=k++;
                }
                while (head<=tail && j-h>q[head]) head++;
                dp[j]=f[q[head]]+fire[i].b-abs(fire[i].a-j);
            }
        }
        for (int i=1; i<=n; i++) ans=max(ans,dp[i]);
        cout<<ans<<endl;
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    MySql常用数据操作
    使用requests+BeaBeautiful Soup爬取妹子图图片
    抓取猫眼电影排行
    Exec执行拼接字符串时遇到的问题及Sql执行函数时需要注意的事项
    c#小知识点
    MVVM 与 sql
    Dictionary
    sql表信息查询
    XAML特殊字符
    编程细节
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13272427.html
Copyright © 2011-2022 走看看