zoukankan      html  css  js  c++  java
  • CDOJ 1132 酱神赏花 dp+单调栈降低复杂度+滚动数组

    酱神赏花

    Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 262143/262143KB (Java/Others)
     

    酱神去杭州赏花。

    花展在一条街道上举行,这条街道上有一共有n个节点,自左而右从11到nn编号,11号和nn号是左右两个端点,两个相邻端点之间的距离为11.本次花展一共要展出mm朵花,在第titi时刻,有一朵颜值为bibi的花将在第aiai个节点展出,如果酱神在titi时刻处于第xx个节点,那么他能获得的开心值为bi|xai|bi−|x−ai|,注意这个值可能为负。

    t=1t=1的时刻,酱神可以随意从11到nn选出一个节点作为赏花的起点。在接下来的每个单位时间段中,酱神最多能移动dd的距离。酱神每秒只能移动整数个距离,且任何时刻不能超出街道的范围。

    他能获得的最大开心值为多少?

    Input

    第一行33个数n,m,dn,m,d。

    接下来mm行,每行33个数ai,bi,tiai,bi,ti。

    1n1051≤n≤105,1m1001≤m≤100

    1ain1≤ai≤n

    1bi1091≤bi≤109

    1ti1091≤ti≤109

    1d1091≤d≤109

    Output

    输出一个数,酱神的最大开心值。

    Sample input and output

    Sample InputSample Output
    30 4 2
    27 3 1
    11 4 1
    11 4 1
    1 2 20
    
    -3
    

    Source

    2015 UESTC Training for Dynamic Programming
    题意:在数轴上有1-n的n个点,共有m多花要开放,每次会在ti时刻在ai位置开出一朵颜值为bi的花
    假如花开时你在x处,那么你得到的颜值是bi-(ai-x),你单位时间移动的速度为d,为你能获得的最大颜值。
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <algorithm>
    #include <set>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long Ull;
    #define MM(a,b) memset(a,b,sizeof(a));
    const double eps = 1e-10;
    const int  inf =0x7f7f7f7f;
    const double pi=acos(-1);
    const int N=100005;
    
    struct node{
       int a,b;ll t;
    }flower[N];
    
    bool cmp(node a,node b)
    {
       return a.t<b.t;
    }
    
    ll dp[N][3];
    int n,m,d,x[N];
    
    void init(int cur)
    {
        for(int i=1;i<=n;i++) dp[i][cur]=-1e15;
    }
    
    int main()
    {
        while(~scanf("%d%d%d",&n,&m,&d))
        {
            for(int i=1;i<=m;i++)
                scanf("%d%d%lld",&flower[i].a,&flower[i].b,&flower[i].t);
            sort(flower+1,flower+m+1,cmp);
    
            int cur=0;
            for(int i=1;i<=n;i++)
                {
                    dp[i][cur]=flower[1].b-abs(flower[1].a-i);
                }
    
            for(int k=2;k<=m;k++)
            {
                cur^=1;
                init(cur);
                ll limit=(flower[k].t-flower[k-1].t)*d;
                int l=1,r=1;
                for(int i=1;i<=n;i++)
                {
                    while(l<r&&dp[i][cur^1]>=dp[x[r-1]][cur^1])  r--;
                    x[r]=i;r++;
                    while(l<r&&(i-x[l]>limit))  l++;
                    dp[i][cur]=max(dp[i][cur],dp[x[l]][cur^1]+flower[k].b-abs(flower[k].a-i));
                }
    
                l=1;r=1;
                for(int i=n;i>=1;i--)
                {
                    while(l<r&&dp[i][cur^1]>=dp[x[r-1]][cur^1])  r--;
                    x[r]=i;r++;
                    while(l<r&&(x[l]-i>limit))  l++;
                    dp[i][cur]=max(dp[i][cur],dp[x[l]][cur^1]+flower[k].b-abs(flower[k].a-i));
                }
            }
    
            ll ans=-1e15;
            for(int i=1;i<=n;i++) ans=max(ans,dp[i][cur]);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    

      分析:经典的一道题,

    1.首先预处理出第一次花开时,枚举在1-n各个点能获得的颜值。

    2.dp[i][k]即为第k次花开时,人在i处获得的最大颜值,那么从小到大枚举每个i,并且维护一个从左到右的单调递减栈(第k-1多花开时),再判断当前枚举的i在单调栈中能达到的最左的点(限制条件就是人转移的距离),然后再从最左点转移一下到当前枚举的点i;

    3.最后因为一个点可以从左边转移过来,也可以从右边转移过来,所以需要i从n到1再进行一次2步骤

    这道题目能用单调栈降下来,关键是因为加入i跟i-1都能转移到j位置,那么如果dp[i][k-1]>=dp[i-1][k-1]的话,那么i-1这个点就不要判断了,直接丢掉

  • 相关阅读:
    十天冲刺4
    单词统计
    十天冲刺3
    学习进度第十周
    十天冲刺2
    十天冲刺1
    梦断代码阅读笔记03
    学习进度第九周
    [强网杯 2019]Upload
    [2020 新春红包题]1
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5766766.html
Copyright © 2011-2022 走看看