CodeForces(C. Watching Fireworks is Fun)DP单调队列优化

在这里插入图片描述

题意:有一个小镇,有1~n共 n 处位置,有 m 个烟花表演,第 i 个烟花会在第 ti 时间绽放,绽放位置为 ai,你在每个时刻会在某个位置 w,当第 i 个烟花绽放时,你处在位置 w,你会得到 bi-|ai-w| 的高兴值,你每个单位时间可移动0 ~ d个长度,求 m 场烟花表演后最大的高兴值和最大为多少

定义d[i][j]为第i场烟花在位置j时的最大高兴值和为多少
显然d[i][j]由d[i-1][k]的max转移过来,k为 j-(t[i]-t[i-1])*d ~ j+(t[i]-t[i-1])*d
因此用一个单调队列维护d[i-1]的k区间的最大值

代码:

#include <bits/stdc++.h>
#define ll long long
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
template<class T> inline void read(T &x){
    
    
    x=0; register char c=getchar(); register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=x*10+c-'0',c=getchar(); if(f)x=-x;
}
using namespace std;

ll n,m,d,dis,op,val,mdx;
ll a[505],b[505],t[505];
ll f[150002];
ll savemax[250005];
ll qmax[250005];
void pp()
{
    
    
    ll ans=-999999999999999999;
    for(int j=1;j<=n;j++)
    {
    
    ans=max(ans,f[j]);}
    cout<<ans<<endl;
}
void RMQ(ll dis)//单调队列维护f(i-1)定长区间最值
{
    
    
    if(dis==0)
    {
    
    
        for(int j=1;j<=n;j++)
        {
    
    savemax[j]=f[j];}
        return;
    }
    ll ds=1,dw=0;
    for(int j=1;j<=n;j++)
    {
    
    
        while(ds<=dw&&f[j]>=f[qmax[dw]])
        {
    
    dw--;}
        qmax[++dw]=j;
        if(j>=dis)
        {
    
    
            while(qmax[ds]<=(j-dis)){
    
    ds++;}
            savemax[j]=f[qmax[ds]];
        }
    }
    if(dis>n){
    
    dis=n+1;}
    ll maxx=f[1];
    savemax[1]=maxx;
    for(int j=2;j<dis;j++)
    {
    
    
        if(f[j]>maxx)
        {
    
    maxx=f[j];}
        savemax[j]=maxx;
    }
}
int main()
{
    
    
    IOS
    cin>>n>>m>>d;
    for(int i=1;i<=m;i++)
    {
    
    cin>>a[i]>>b[i]>>t[i];}
    for(int j=1;j<=n;j++)
    {
    
    f[j]=b[1]-abs(a[1]-j);}
    if(m==1){
    
    pp();return 0;}//只有一场烟花
    dis=(t[2]-t[1])*d+1;
    RMQ(dis);
    for(ll i=2;i<=m;i++)
    {
    
    
        op=(t[i]-t[i-1])*d;
        for(ll j=1;j<=n;j++)
        {
    
    
            val=b[i]-abs(a[i]-j);
            mdx=min(j+op,n);
            f[j]=max(savemax[mdx],savemax[j])+val;
        }
        if(i==m){
    
    pp();break;}
        dis=(t[i+1]-t[i])*d+1;
        RMQ(dis);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43781431/article/details/108084604