惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tor Project blog
B
Blog RSS Feed
M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
H
Hackread – Cybersecurity News, Data Breaches, AI and More
罗磊的独立博客
GbyAI
GbyAI
N
Netflix TechBlog - Medium
博客园 - 司徒正美
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
W
WeLiveSecurity
Stack Overflow Blog
Stack Overflow Blog
Y
Y Combinator Blog
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Register - Security
The Register - Security
Cisco Talos Blog
Cisco Talos Blog
Martin Fowler
Martin Fowler
A
About on SuperTechFans
S
Security @ Cisco Blogs
T
Tenable Blog
C
Check Point Blog
N
News and Events Feed by Topic
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Attack and Defense Labs
Attack and Defense Labs
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Cisco Blogs
P
Palo Alto Networks Blog
V
V2EX
博客园 - 聂微东
Project Zero
Project Zero
酷 壳 – CoolShell
酷 壳 – CoolShell
D
Docker
N
News | PayPal Newsroom
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
小众软件
小众软件
Application and Cybersecurity Blog
Application and Cybersecurity Blog
人人都是产品经理
人人都是产品经理
V2EX - 技术
V2EX - 技术
I
Intezer
L
LINUX DO - 最新话题

博客园 - 糖豆爸爸

【树上DP前导知识汇总】 快速幂、龟速乘总结 反向建图+拓扑排序 卡特兰数专题(Catalan) AcWing 126. 最大的和 AcWing 414. 数字游戏 AcWing 468. 魔法阵 AcWing 463. 求和 洛谷 P1632 点的移动 P1056 NOIP2008 普及组 排座椅 洛谷 P1889 士兵站队 洛谷 P1862 输油管道问题 CF444C DZY Loves Colors P2253 好一个一中腰鼓! SCOI2010 P2572 序列操作 P4344 SHOI2015 脑洞治疗仪 T125847 【模板】动态开点线段树 P3373 【模板】线段树 2 Physical Education Lessons
AcWing 431. 守望者的逃离
糖豆爸爸 · 2023-09-28 · via 博客园 - 糖豆爸爸

\(AcWing\) \(431\). 守望者的逃离

一、题目描述

恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变。

守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大岛上。

为了杀死守望者,尤迪安开始对这个荒岛施咒,这座岛很快就会沉下去。

到那时,岛上的所有人都会遇难。

守望者的 跑步速度\(17m/s\),以这样的速度是无法逃离荒岛的。

庆幸的是守望者拥有 闪烁法术,可在 \(1s\) 内移动 \(60m\),不过每次使用闪烁法术都会 消耗魔法值 \(10\)

守望者的魔法值恢复的速度为 \(4\) 点/\(s\),只有 处在原地休息状态时才能恢复

现在已知守望者的魔法初值 \(M\),他所在的初始位置与岛的出口之间的距离 \(S\),岛沉没的时间 \(T\)

你的任务是写一个程序帮助守望者计算如何在 最短的时间内 逃离荒岛,若不能逃出,则输出守望
者在剩下的时间能走的最远距离。

注意:守望者跑步、闪烁或休息活动均以秒(\(s\))为单位,且每次活动的持续时间为整数秒。距离的单位为米(\(m\))。

输入格式
输入文件仅一行,包括空格隔开的三个非负整数 \(M,S,T\)

输出格式
输出文件包括两行:

\(1\) 行为字符串 YesNo(区分大小写),即守望者是否能逃离荒岛。

\(2\) 行包含一个整数,第一行为 Yes 时表示守望者逃离荒岛的最短时间;第一行为 No 时表示守望者能走的最远距离。

数据范围
\(1≤T≤300000,0≤M≤1000,1≤S≤10^8\)

输入样例

39 200 4

输出样例

No
197

输入样例#2

36 255 10

输出样例#2

Yes
6

二、解题思路

机房\(dalao\):一看就是弱智\(dp\)题。然后他切了。但是我因为太菜第一想法是全都进行闪现。下面进行分析。

每次恢复魔力值\(10\)点需要\(2.5s\),再用\(1s\)进行\(60m\)的闪现,\(60/3.5\)大概是\(17.14m/s\)的速度,刚出发的时候还有一些魔力值。跑步速度是\(17m/s\),这样看来似乎闪现是最优选,我们愉快的贪心吧!!于是我立马写了个代码交上:

#include <bits/stdc++.h>
using namespace std;
int m; // 初始魔法值
int s; // 他所在的初始位置与岛的出口之间的距离
int t; // 岛沉没的时间
int d; // 守望者在剩下的时间内能走的最远距离

// 贪心思路,可能过 5/11
int main() {
    cin >> m >> s >> t;
    for (int i = 1; i <= t; i++) { // 枚举每一秒
        if (m >= 10) {             // 如果剩余魔法值大于10,那么可以进行闪烁
            m -= 10;               // 魔法值减10
            d += 60;               // 距离增加60
        } else
            m += 4; // 停下来,消耗1秒,魔法值恢复4点

        if (d >= s) {              // 如果走的距离已经大于目标距离,可以走出
            cout << "Yes" << endl; // 说明可以走出去
            cout << i << endl;     // 输出需要几秒
            return 0;
        }
    }
    cout << "No" << endl; // 走不出去
    cout << d << endl;    // 最远可以走到d这个位置上
    return 0;
}

很好,样例都没过。但是我怎么可能这么轻易认输呢,我干脆点了提交。

虽然\(WA\)了一半,但\(A\)了一半说明它并不是全无道理。或许可以推出正确的思路呢?

以样例为例,39 200 4这组数据正确的最远距离结果是\(197\),这份代码输出的结果则是\(180\).我们可以看出来,最后一秒中本可以跑步\(17m\),这份代码却会让守望者原地等待。

再看36 255 10这组,正确的最短时间是\(6s\),这份程序的结果是\(9s\)。我们人工模拟一下,可以发现在\(5s-6s\)时我们可以选择跑步啊!而这个废物代码却会原地等待\(3s\)后再进行闪现。

这时我又觉得我会了!只要判断一下不就好了吗!

#include <bits/stdc++.h>
using namespace std;

int m; // 初始魔法值
int s; // 他所在的初始位置与岛的出口之间的距离
int t; // 岛沉没的时间
int d; // 守望者在剩下的时间内能走的最远距离

int main() {
    cin >> m >> s >> t;
    for (int i = 1; i <= t; i++) { // 枚举每一秒
        if (s - d <= 17) {         // 如果距离小于17,那么可以在1秒内跑步走完,不用再等魔法值恢复
            cout << "Yes" << endl; // 说明可以走出去
            cout << i << endl;     // 输出需要几秒
            return 0;
        }

        if (i == t && m < 10) { // 时间到达最后1秒,还剩下1秒的时间,并且不足以进行一次闪烁
            cout << "No" << endl;
            cout << d + 17 << endl; // 这1秒跑步吧
            return 0;
        }

        if (m >= 10) { // 能闪烁尽量闪烁
            m -= 10;   // 用一次闪烁,魔法值就减少10个
            d += 60;   // 能跑60米
        } else
            m += 4; // 本秒用于回血,1秒可以恢复4个血

        if (d >= s) {
            cout << "Yes" << endl; // 说明可以走出去
            cout << i << endl;     // 输出需要几秒
            return 0;
        }
    }
    cout << "No" << endl; // 走不出去
    cout << d << endl;    // 最远可以走到d这个位置上
    return 0;
}

好,这次看起来好多了,我们再提交一下试试。

只是多\(A\)了一个点,说明优化还是有问题。思考过后我们可以想到,每秒中我们有三种决定:闪现、跑步和停留。停留和闪现可以合并在一起,我们的优化只给了最后一秒跑步的选择

于是我们可以运用一种似乎很像动态规划的解法啦!我们先假设全部进行闪现-停留-闪现操作,再加一个循环判断每秒的最优决策究竟是闪现-停留还是跑步。我们用\(f[i]\)数组表示第\(i\)秒时守望者 所能到的最远距离

#include <iostream>
using namespace std;
const int N = 300010;
int m;    // 初始魔法值
int s;    // 他所在的初始位置与岛的出口之间的距离
int t;    // 岛沉没的时间
int f[N]; // f[i]数组表示第i秒时守望者所能到的最远距离

int main() {
    cin >> m >> s >> t;
    for (int i = 1; i <= t; i++) { // 相当于第一次提交的程序
        if (m >= 10) {             // 能闪烁尽量闪烁
            m -= 10;
            f[i] = f[i - 1] + 60; // 最大距离可以增加60米
        } else {
            m += 4;          // 不能闪烁,那么就站在原地回血
            f[i] = f[i - 1]; // 距离没有长大
        }
    }
    // 问题是站在原地回血不一定是最优选择,也可以在此时选择跑步啊~
    for (int i = 1; i <= t; i++) {
        f[i] = max(f[i], f[i - 1] + 17); // 如果在第i秒时跑步能到达更远距离,我们跑步
        if (f[i] >= s) {                 // 已到达就可以输出+结束程序啦
            cout << "Yes" << endl;
            cout << i << endl;
            return 0;
        }
    }
    cout << "No" << endl;
    cout << f[t] << endl; // 如果进行到了这里说明无法逃离,我们输出能到达的最远距离
    return 0;
}

这次的样例也过了,于是我们提交一下。

一道黄题耗我十五分钟我果然还是太菜了

这样就通过了!如果有兴趣的话大家可以研究一下暴力写法,也是能过的(我懒得想了

谨记教训:犹豫就会败北,果断就会白给!!!