• [POI 2014]PTA-Little Bird


    Description

    题库连接

    给你 (n) 棵树,第 (i) 棵树的高度为 (d_i)。有一只鸟从 1 号树出发,每次飞跃不能超过 (k) 的距离。若飞到下一棵树的高度大于等于这一棵树那么耗费一点体力,否则不会。问你飞到第 (n) 棵树耗费最少体力为多少。多测,测试组数 (q)

    (1leq nleq 10^6,1leq qleq 25)

    Solution

    朴素的 (O(n^2)) DP 是很容易想到的,记 (f_i) 表示飞到 (i) 上的最小花费。那么,(f_i=minlimits_{i-jleq k} f_j+[d_igeq d_j])

    容易发现,最优的答案一定可以从所有满足条件的 (j)(f_j) 最小的地方转移过来,即 (f_i) 的值只可能是 (minlimits_{i-jleq k} f_j)(minlimits_{i-jleq k} f_j+1)

    那么可以开一个单调队列维护满足条件的 (j),并且满足 (f) 单调;在 (f) 相同的同时 (d) 单调递减(从越高的树转移越优)。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6+5;
    
    int n, t, a[N], k, q[N], head, tail, f[N];
    
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &k); 
            q[head = tail = 1] = 1;
            for (int i = 2; i <= n; i++) {
                while (i-q[head] > k) ++head;
                f[i] = f[q[head]]+(a[q[head]] <= a[i]);
                while (head <= tail && (f[i] < f[q[tail]] || (f[i] == f[q[tail]] && a[i] >= a[q[tail]]))) --tail;
                q[++tail] = i;
            }
            printf("%d
    ", f[n]);
        }
        return 0;
    }
  • 相关阅读:
    闲谈随笔以及对自己的心里暗示
    java利用Scanner获取键盘输入
    【积累】发送验证码按钮倒计时js
    【积累】validate验证框架的使用
    重写toString()方法来描述一个类
    【java基础】 合并两个类型相同的list
    java单例类/
    基本类型的包装类
    强转
    【java基础】面向对象的三大特征---多态
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/12238386.html
Copyright © 2020-2023  润新知