【[POI2014]PTA-Little Bird】

本文介绍了一种使用贪心策略解决小鸟跳跃问题的方法,通过优化选择路径,以最小化跳跃过程中的体力消耗。文章详细阐述了算法的实现思路,并提供了C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力。

显然这道题可以用贪心做,而且多数情况时间复杂度比用单调队列优化DP低得多(当然DP也自有它的好处,比如不容易被卡常)

我们用d表示树的编号,假设小鸟现在在d[i]的树,在所有可飞跃的树中(d[i+1]~d[i+k]),按以下策略选择:

优先考虑d[j]<d[i]的d[j],选择最大的d[j],如果有多个d[j]最大,选择最大的j。

如果没有d[j]<d[i]的d[j],只能考虑d[j]>=d[i]的d[j],同样选择最大的d[j],如果有多个d[j]最大,选择最大的j。

贪心的正确性显然。

代码实现:

#include <cstdio>

const int MAXN = 1000000;

//快读 
inline int read() {     
    int x = 0, f = 1;     
    char s;     
    while((s = getchar()) < '0' || s > '9')     
        if(s == '-')      
            f = -1;     
    while(s >= '0' && s <= '9')     
        x = (x << 3) + (x << 1) + (s ^ '0'), s = getchar();     
    return x * f;     
} 

//快输 
inline void write(int x) {  
    if(x < 0)   
        x = -x, putchar('-');  
    if(x / 10)  
        write(x / 10);  
    putchar(x % 10 + '0');  
} 

int n, q;
int d[MAXN + 5], k[MAXN + 5];

inline int answer(const int x) { //这里的x代表k[i] 
    int ans = 0; 
    int i = 1; //小鸟一开始的位置为1 
    while(true) {
        if(i + x >= n)  { //如果当前小鸟的位置可以直接飞到终点,由于不可能有比直接飞到终点的情况更优,所以直接飞到终点
            if(d[n] >= d[i]) //如果终点大于小鸟的位置,答案就加1 
                ++ans;
            break;
        }
        bool flag = true; //表示能否找到小于d[i]的d[j] 
        int maxn = 0, numn;
        for(int j = i + x; j > i; j--) { 
            if(d[j] < d[i]) {
                flag = false; //找到就把flag置为false 
                if(d[j] > maxn) //倒序找则不能取等,因为要求最大的j 
                    maxn = d[j], numn = j; //找到最大最远的小于d[i]的d[j] 
            }
        }
        if(flag) { //如果没有d[j]小于d[i] 
            int Max = 0, num;
            for(int j = i + x; j > i; j--)
                if(d[j] > Max)
                    Max = d[j], num = j; //找到最大最远的d[j] 
            ++ans; //没有d[j]小于d[i],则答案必须加1 
            i = num; //将小鸟的位置变为符合策略的j 
        } else {
            i = numn; //同上 
        }
    }
    return ans; 
}

int main() {
    n = read();
    for(int i = 1; i <= n; i++)
        d[i] = read();
    q = read();
    for(int i = 1; i <= q; i++)
        k[i] = read(); //不喜欢边输入边输出,所以用数组存 
    for(int i = 1; i <= q; i++) {
        int ans = answer(k[i]); 
        write(ans), putchar('\n'); //输出答案 
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值