zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    js,vue.js一些方法的总结
    confirm提示弹出确定和取消按钮
    移动端 meta 必备
    Vue.js总结 [2017.6.5]
    2017.6.5项目总结(移动端touch事件)
    微信公众平台接口开发(全面认识接口)
    数据库作业
    数据库子函数等
    判断一年是否为闰年
    数据库练习
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/11199338.html
Copyright © 2011-2022 走看看