zoukankan      html  css  js  c++  java
  • zstu 4237 马里奥的求救——(单调队列DP)

      题目链接:http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4237

      这题可以转化为每次可以走g~d+x步,求最大分数,且最大分数的步数最少。

      这题的数据范围比较小,可以用奇怪的姿势过。

      首先,lyf队长给的方法是n^3的dp过;用我自己的方法是搜索也可以过,因为数据小。

      但是,如果数据范围很大,就得用复杂度是O(n)的单调队列dp来做。

      上次做过一道单调队列的dp问题,当时比较懵懂,现在,对这个方法有了更深的理解。而且,只要把id丢进单调队列里即可(因为可以通过id查找dp的值)。具体过程还是看代码仔细理解吧:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <queue>
     4 #include <set>
     5 using namespace std;
     6 typedef pair<int,int> pii;
     7 
     8 const int inf =0x3f3f3f3f;
     9 int n,x,g,d;
    10 int a[100+5];
    11 pii dp[100+5];
    12 
    13 pii solve()
    14 {
    15     deque<int> Q;
    16     dp[0]=pii(0,0);
    17     for(int i=1;i<=n;i++)
    18     {
    19         while(!Q.empty() && Q.front()<i-d) Q.pop_front();
    20         if(i-g>=0 && dp[i-g].first != -inf)
    21         {
    22             while(!Q.empty() && dp[Q.back()] <= dp[i-g]) Q.pop_back();
    23             Q.push_back(i-g);
    24         }
    25         if(!Q.empty()) dp[i] = pii(dp[Q.front()].first + a[i],dp[Q.front()].second - 1);
    26         //因为题目要求最大分数的最小步数,而对pair的max是默认取大的值,
    27         //所以取个反就是最大化(-步数)
    28         else dp[i] = pii(-inf,0);
    29     }
    30     pii ret = pii(-inf,0);
    31     for(int i=0;i<=n;i++)
    32     {
    33         if(i>=n-d+1) ret=max(ret,dp[i]);
    34         //如果处于再跳一步就可以出去的状态的话
    35     }
    36     ret.second = -ret.second + 1;
    37     //加1是细节,因为还需要一步跳出
    38     return ret;
    39 }
    40 
    41 int main()
    42 {
    43     int T;
    44     scanf("%d",&T);
    45     while(T--)
    46     {
    47         scanf("%d%d%d%d",&n,&x,&g,&d);
    48         d += x;
    49         for(int i=1;i<=n;i++) scanf("%d",a+i);
    50         pii ans = solve();
    51         printf("%d %d
    ",ans.first,ans.second);
    52     }
    53     return 0;
    54 }

      同时,因为pair的比较方法,这里必须把步数转换成负数的。如果不这样就必须写比较器:

    1 bool operator < (const std::pair<int,int> &a,const std::pair<int,int> &b) {
    2     if (a.first != b.first) return a.first < b.first;
    3     return a.second > b.second;
    4 }
    5 
    6 bool operator <= (const std::pair<int,int> &a,const std::pair<int,int> &b) {
    7     return a == b || a < b;
    8 }

      也可以用写cmp的方式,像sort一样传入第三个参数cmp,同时把dp[Q.back()] <= dp[i-g]改成(max(dp[Q.back()],dp[i-g],cmp) == dp[i-g]) 就行,但是不如上面那样写比较器来的逻辑清晰。

      同时,这题有个奇怪的地方在于,重载了以后max还是会出错,必须 if (ret < dp[i]) ret = dp[i];来代替max才行。但是,自己试验了别的代码以后发现,重载了以后max函数是可以生效的,这里真是有毒啊。还是”留坑以后填“吧。。

  • 相关阅读:
    JSONHelper
    win pe 修改xp系统开机密码方法
    Microsoft SQL Server 2008 安装图解(Windows 7)
    ORA-00368 ORA-00353 ORA-00312
    Oracle和MSSQL查询有多少张表
    css技巧总结
    保持宽高比的宽度自适应盒子
    css选择器位置和数量技巧
    inline-block元素垂直对齐
    webpack编译vue出现dev警告
  • 原文地址:https://www.cnblogs.com/zzyDS/p/5623346.html
Copyright © 2011-2022 走看看