首页 > 其他分享 >AcWing 431. 守望者的逃离

AcWing 431. 守望者的逃离

时间:2023-09-28 09:33:49浏览次数:151  
标签:10 魔法值 int 守望者 60 跑步 AcWing 431

\(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;
}

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

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

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

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

标签:10,魔法值,int,守望者,60,跑步,AcWing,431
From: https://www.cnblogs.com/littlehb/p/17734879.html

相关文章

  • AcWing 414. 数字游戏
    \(AcWing\)\(414\).数字游戏一、题目描述丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共\(n\)个),你要按顺序将其分为\(m\)个部分,各部分内的数字......
  • AcWing 463. 求和
    \(AcWing\)\(463\).求和一、题目描述一条狭长的纸带被均匀划分出了\(n\)个格子,格子编号从\(1\)到\(n\)。每个格子上都染了一种颜色\(color_i\)(用\([1,m]\)当中的一个整数表示),并且写了一个数字\(number_i\)。定义一种特殊的三元组:\((x,y,z)\),其中\(x,y,z\)都代表纸......
  • 第九十八场周赛. AcWing 4949. 末尾连续0
    第九十八场周赛.AcWing4949.末尾连续0给定一个正整数\(m\),请你统计一共有多少个正整数\(n\)满足,\(n\)的阶乘的末尾连续\(0\)的数量恰好为\(m\)。输出满足条件的\(n\)的数量以及所有满足条件的\(n\)。例如,当\(m=1\)时,满足条件的正整数\(n\)共有......
  • 第九十八场周赛. AcWing 4948. 大乘积
    第九十八场周赛.AcWing4948.大乘积我们规定,如果一个非负整数\(a\)满足以下两个条件之一,则称\(a\)为美丽数:\(a=0\)\(a=10^x\),其中\(x\)为任意非负整数。给定\(n\)个非负整数\(a_1,a_2,…,a_n\),这其中有至少\(n−1\)个数是美丽数。请你计算并输出\(a_......
  • AcWing 896. 最长上升子序列 II
    题目给定一个长度为$N$的数列,求数值严格单调递增的子序列的长度最长是多少。输入格式第一行包含整数$N$。第二行包含$N$个整数,表示完整序列。输出格式输出一个整数,表示最大长度。数据范围$1≤N≤100000,−10^9≤数列中的数≤10^9$输入样例:73121856输出样例......
  • Acwing 周赛110 5046
    Acw5046思路dp,\(dp_i\)表示前i种药且吃第i种药使智商达到\(r_i\)的方案,根据题意可知\[dp_i=\sumdp_j,(r_j\in[l_i,r_i-1])\]先将各区间按右端点排序,求j的区间可用二分.代码//9.24intn,m,k;intf[N],s[N];//acw110structseg{ intl,r; booloperator<(c......
  • Acwing. 第122场周赛
    比赛链接A简单输出题目链接简单的模拟一下就好了,注意是多组样例就行。#include<bits/stdc++.h>usingnamespacestd;voidsolve(){intn;cin>>n;for(inti=1;i<=n;i++){cout<<i<<"";}cout<<endl;}intmain(){......
  • 容斥原理应用Acwing890借鉴题解
    参考文献简单的容斥原理介绍请看下图:C++代码简单的容斥原理介绍请看下图:本题思路:将题目所给出的m个数可以看成是m位的二进制数,例如当p[N]={2,3}时,此时会有01,10,11三种情况而二进制的第零位表示的是p[0]上面的数字2,第1位表示p[1]上面的数字3所以当i=1时表示只选择2的......
  • Acwing393. 雇佣收银员 题解 差分约束
    题目链接:https://www.acwing.com/problem/content/description/395/解题思路:差分约束。为了方便起见,定义第\(i\)个时间段为\(i-1:00\)到\(i:00\)这个时间段。首先,为了方便开一个额外的点,令\(R_i\)对应为题目中的\(R(i+1)\),即\(R_i\)表示\(i-1:00\)到\(i:00\)这......
  • Acwing 5220
    Acw5220题意自己看思路假设串N长度为\(n\),串H长度为\(m\),遍历串H,对于\([i,i+n-1]\)这一段子串,如果所含字母个数与串N所含字母个数相同,则认为匹配,问题在于如何判断排列重合的问题。字符串哈希。匹配的话直接将这一段的哈希值放入set中,去重,最后set的size就是答案代码const......