F

C. Watching Fireworks is Fun

题目大意:

一个城镇有n个区域,从左到右1-n,每个区域之间距离1个单位距离。节日中有m个烟火要放,给定放的地点a[ i ]、时间t[ i ] ,如果你当时在区域x,那么你可以获得b[ i ] - | a[ i ] - x |的happiness 。你每个单位时间可以移动不超过d个单位距离,你的初始位置是任意的,求你通过移动能获取到的最大的happiness值。

我感觉很难,而且其实也不是特别熟悉单调队列,对于单调队列的运用也不是特别熟练。

这个题目首先你要找状态,这个状态就是时间和位置,所以我们可以先定义 dp[i][j] 表示第 i 时刻在位置 j 的最大幸福值。

但是这个时间有 1e9 不过只有300个物品,就是可以离散化一下,就只有300了,但是位置有150000 这个放进dp数组还是超时了。

不过每一个时间只和上一个时间有关系,所以这个时候就可以用滚动数组了,所以最后就是dp[2][2e5]

这个题目为什么要用单调队列呢,因为如果不是同一时刻绽放的烟花,是有移动距离的,这一段距离的最大幸福度就可以用单调队列来找到。

这个就是我们枚举每一个 j 的位置,上一个烟花在 j 两边左右为 d*t 的距离绽放都是可以让这一个烟花在 j 位置绽放。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
typedef long long ll;
//首先枚举每一个物品,然后再去dp转移找到这个物品的最优解,就是abs(a[i]-x)的最小值
//具体就是用一个来表示时间的转移,然后对于每一个物品,如果这个时间恰好是烟花绽放的时间,那就直接从上一个转移过来
//如果不是,就是说明有一段路可以走,那就用单调队列,维护每一个点的一段区间的最大值
ll que[maxn], dp[2][maxn];
ll a[maxn], b[maxn], t[maxn];

int main()
{
    ll n, m, k;
    scanf("%lld%lld%lld", &n, &m, &k);
    for (int i = 1; i <= m; i++) scanf("%lld%lld%lld", &a[i], &b[i], &t[i]);
    ll pretime = t[1];
    int id = 0;
    for(int i=1;i<=m;i++)
    {
        if(pretime==t[i])
        {
            for(int j=1;j<=n;j++)
            {
                dp[id][j] = dp[id ^ 1][j] + b[i] - abs(a[i] - j);
            }
        }
        else
        {
            ll x = t[i] - pretime;
            pretime = t[i];
            int f1 = 1, t1 = 0;
            int r = 1;
            for(int j=1;j<=n;j++)
            {
                while(r<=n&&r<=x*1ll*k+j)
                {
                    while (t1 >= f1 && dp[id ^ 1][r] > dp[id ^ 1][que[t1]]) t1--;
                    que[++t1] = r++;
                }
                while (f1 <= t1 && que[f1] < j - x * k) f1++;
                dp[id][j] = dp[id ^ 1][que[f1]] + b[i] - abs(a[i] - j);
            }
        }
        id ^= 1;
    }
    ll ans = -inf64;
    for (int i = 1; i <= n; i++) {
        ans = max(ans, dp[id ^ 1][i]);
    }
    printf("%lld
", ans);
    return 0;
}
单调队列优化dp
原文地址:https://www.cnblogs.com/EchoZQN/p/11199338.html