uva12170 Easy Climb

我觉得这个题挺难的......
首先这个题的结论 hp+kd我没有证明出来(范围肯定没有问题,根据数量少的时候和感觉就觉得是对的,但是没有严格的证明)

dp[i][x]就是在dp[i-1][x-d---x+d]中找一个最小值转移,再加上常数|h[i]-x|,这样就可以用优先队列来优化。
虽然说是用单调队列来求每个滑动窗口的最小值,然而再深入分析一步就会发现一个规律,每次算完一个阶段后,该阶段的dp序列呈现的是一个先下降,后上升的趋势,而且下降时候的最低点一定是整个序列的最低点。这样,我们只需要一个front指针即可维护优先队列了。

先维护窗口左边界,别让指针k超出了窗口,如果x[k] < x[j] - d那么就k++ (因为x数组是从大到小已经排好序的),然后在不超出右边界x[j]+d 的前提下,如果dp[i][k+1] <= dp[i][k],那么k++;

为什么这样是对的的? 好像和之前说的单调队列一点也不一样啊! ?其实是一样的操作,仔细回想维护单调队列时是怎么操作的 :用两个指针front、rear 先更新左边界,防止他超出边界,一旦超出就front++; 然后每次新加进来一个值就要看看当前队列最右端的元素与新值的大小,如果大于新值那么就rear--,将无用的元素请出队列 ,直到小于新值,就将新值加入, 然而其实上边那个用一个指针的方法是如出一辙的,只不过将删除无用值这一步放到了求最小值时,也就是更新k时 。


unique函数属于STL中比较常用函数,它的功能是元素去重。即”删除”序列中所有相邻的重复元素(只保留一个)。此处的删除,并不是真的删除,而是指重复元素的位置被不重复的元素给占领了(详细情况,下面会讲)。由于它”删除”的是相邻的重复元素,所以在使用unique函数之前,一般都会将目标序列进行排序。返回iterator

 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

typedef long long LL;

const int maxn = 100 + 5;
const int maxx = maxn*maxn*2;
const LL  INF = (1LL << 60);

LL h[maxn], x[maxx], dp[2][maxx];

int main () {
  int T;
  cin >> T;
  while(T--) {
    int n;
    LL d;
    cin >> n >> d;
    for(int i = 0; i < n; i++) cin >> h[i];
    if(abs(h[0] - h[n-1]) > (n-1)*d) {
      cout << "impossible\n";
      continue;
    }

    int nx = 0;

    for(int i = 0; i < n; i++)
      for(int j = -n+1; j <= n-1; j++)
        x[nx++] = h[i] + j*d;
    sort(x, x+nx);
    nx = unique(x, x+nx) - x;           ////把所有可能用到的修改结果都存放到x数组中

    int t = 0;
    for(int i = 0; i < nx; i++) {
      dp[0][i] = INF;
      if(x[i] == h[0]) dp[0][i] = 0;
    }
    for(int i = 1; i < n; i++) {
      int k = 0;                          ////因为只有奇,偶两种变化,且i只依赖于i-1时候的情况,因此可以用滚动数组优化
      for(int j = 0; j < nx; j++) {   //从小到大枚举x值,因为所有需要用到的x值都在x数组中,因此等价于枚举下标
                                       //dp[t][j]是这个状态(也就是改了i个数,改成了x[j]的表示)
        while(k < nx && x[k] < x[j]-d) //得到y, 前一个的高度
            k++;
        while(k+1 < nx && x[k+1] <= x[j]+d && dp[t][k+1] <= dp[t][k]) //这里其实是单调队列
            k++; // min in sliding window
        if(dp[t][k] == INF)
            dp[t^1][j] = INF;//之前的y都没有,肯定达不到目前的x
        else
            dp[t^1][j] = dp[t][k] + abs(x[j] - h[i]);  //得到x[j]处对应的最小值   j递增,abs就先减后增,(t,k)也先减后增
      }
      t ^= 1;
    }
    for(int i = 0; i < nx; i++)
      if(x[i] == h[n-1])
        cout << dp[t][i] << "\n";
  }
  return 0;
}

 

转载于:https://www.cnblogs.com/lqerio/p/9800700.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
只上攀是一个非常有趣和创新的整蛊直播搭建工具和教程。它为用户提供了一个简单而有趣的平台,可以让他们体验整蛊直播的乐趣和刺激。 整蛊直播是一种流行的网络娱乐形式,通过演绎故事和设置整蛊情节,可以给观众带来笑声和惊喜。只上攀是一个专门为创建整蛊直播场景和故事情节而设计的工具和教程。 这个工具提供了丰富的场景和故事模板,用户只需要根据自己的需求选择合适的模板,然后根据提示进行设置和编辑就可以轻松搭建整蛊直播场景。同时,还可以自定义角色和对白,以及添加音效和特效,从而增强整蛊效果。 只上攀的教程则提供了详细的指导和技巧,帮助用户了解如何利用这个工具进行整蛊直播。教程包括了从基础知识到高级技巧的内容,让用户可以逐步学习和掌握整蛊直播的技巧和方法。 只上攀的优势不仅仅在于它提供了简单易用的搭建工具,还在于它丰富多样的教程内容。无论用户是初学者还是有经验的直播主,都可以从中获得帮助和灵感。 总之,只上攀是一个非常有趣和实用的整蛊直播搭建工具和教程。它能帮助用户轻松搭建整蛊直播场景,并提供详细的教程和技巧,让用户可以掌握整蛊直播的技巧和方法。无论是想要尝试新鲜事物的初学者,还是有经验的直播主,只上攀都是一个值得一试的工具和教程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值