“战疫杯”在线邀请赛——第四场题解

“战疫杯”在线邀请赛——第四场题解

题目详情 - 1 时空密接 (pintia.cn)

在抗击疫情的过程中,我们需要清楚确定密接,而感染者的整个运动过程中和他位置重合的人都将被当作密切接触者,现在就请你设计一个算法计算两个人的轨迹是否有时空密接。

为了简化问题我们把场景当成一个二维坐标系,每个人看作坐标系上的一个整数点,在每一个时刻会原地不动或向上下左右移动一格,我们认为两个人只要在某一时刻出现在了同一个网格中就是时空密接。

输入格式:

第一行包含五个用空格隔开的正整数x1,y1,x2,y2(−109≤x1,y1,x2,y2≤109),t(1≤t≤100),分别代表两个人在0时刻所处的位置,以及接下来的t时刻中的移动路径。

第二行和第三行都是一个长度为t的字符串,分别代表两人在每一时刻的移动轨迹,字符串由大写字母W,S,A,D,O组成,分别代表上下左右移动一格与停止不动,即坐标由(x,y)改变为(x,y+1),(x,y−1),(x−1,y),(x+1,y),(x,y)。

输出格式:

如果两人存在时空密接就输出’yes’,否则则输出’no’(不含引号,且区分大小写)。

输入样例:

1 1 2 2 4
DDDO
DSDD

输出样例:

yes

样例解释

两人的坐标分别为:

(1,1)→(2,1)→(3,1)→(4,1)→(4,1)

(2,2)→(3,2)→(3,1)→(4,1)→(5,1)

因此两人在第2、3时刻在同一位置,属于时空密接。

问题解析

for循环同时遍历两个字符串,并按照字符把他们的位置进行改变,如果同时间下他们两人的位置坐标相等,说明是密接输出yes。如果遍历完还没有相同说明不是密接输出no。

(为了暴力代码写的很丑,望不要嫌弃)

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int x1, x2, y1, y2, m;
    cin >> x1 >> y1 >> x2 >> y2 >> m;
    string s1, s2;
    cin >> s1 >> s2;
    for (int i = 0; i < m; i++)
    {
        if (x1 == x2 && y1 == y2)
        {
            cout << "yes" << endl;
            return 0;
        }
        if (s1[i] == 'D')
        {
            x1++;
        }
        else if (s1[i] == 'A')
        {
            x1--;
        }
        else if (s1[i] == 'S')
        {
            y1--;
        }
        else if (s1[i] == 'W')
        {
            y1++;
        }
        if (s2[i] == 'D')
        {
            x2++;
        }
        else if (s2[i] == 'A')
        {
            x2--;
        }
        else if (s2[i] == 'S')
        {
            y2--;
        }
        else if (s2[i] == 'W')
        {
            y2++;
        }
    }
    if (x1 == x2 && y1 == y2)
    {
        cout << "yes" << endl;
        return 0;
    }
    cout << "no";
    return 0;
}

题目详情 - 2 今晚吃鸡 (pintia.cn)

777777777Plus和SW2000正在游玩一款fps(第一人称射击类)游戏,在游戏中777777777Plus和SW2000需要瞄准射击,当系统判定到击中头部,身体,和四肢时会造成不同的伤害。当击中头部时,会造成100点伤害;当击中胸背部时,会造成30点伤害,当击中四肢时,会造成10点伤害。当血量小于等于0时,游戏结束,血量不为0的一方获胜。

同时该游戏有防具设计,包括头盔(保护头部)和护甲(保护胸背部)。当玩家穿着防具时,对该部位的攻击会由扣除血量改为扣除防具的耐久度。当防具耐久度降低到0时将会破碎失去伤害抵挡效果。

换言之,如果防具当前耐久为x,收到的攻击为y,当x>y时,防具的耐久变为xy,不会破碎。当xy时,防具会破碎,且此次攻击不再扣除玩家血量。

现在,给出777777777Plus和SW2000游戏的记录,你能否算出是谁在游戏中获胜了?

输入格式:

第一行输入三个整数a1,b1,c1(1≤a1≤100,0≤b1,c1≤100),分别表示777777777Plus的剩余血量,护甲耐久度,头盔耐久度。

第二行输入三个整数a2,b2,c2(1≤a2≤100,0≤b2,c2≤100),分别表示SW2000的剩余血量,护甲耐久度,头盔耐久度。

第三行一个n(1≤n≤1000)代表游戏记录条数。

其后n行,每行两个字符串s,t。其中当s是"777777777Plus"(不带引号)时,代表777777777Plus受到了攻击,反之当s是"SW2000"(不带引号)时,代表SW2000受到了攻击。
t是"head"(不带引号)时,代表头部受到攻击,当t是"body"(不带引号)时,代表胸背部受到攻击,当t是"limbs"(不带引号)时,代表四肢受到攻击。

数据保证不存在玩家血量小于等于0后继续攻击的情况。

输出格式:

输出一行一个字符串,“777777777Plus"或者"SW2000”,代表获胜玩家。输出时不需要带引号。

输入样例:

1 1 1
100 0 0
4
777777777Plus head
SW2000 body
777777777Plus body
SW2000 head

输出样例:

777777777Plus

问题解析

注意两个情况:

1、护甲不能保护四肢只能保护胸口

2、哪怕当前伤害大于防具的耐久度,只要耐久度不为0,那么这次伤害就能被挡下

我直接按照题目说的,用a1,b1,c1存777的血量、护甲度和头盔度;a2,b2,c3存SW的血量、护甲度和头盔度。然后根据每一步判断是哪个玩家的那里受了伤,如果对应位置的防具耐久度大于0,就可以当下这次伤害并给防具减去对应的值,如果防具度小于等于0或者没有防具(四肢),那就直接扣血。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int a1, b1, c1, a2, b2, c2;
    cin >> a1 >> b1 >> c1 >> a2 >> b2 >> c2;
    int n;
    cin >> n;
    string s1, s2;
    while (n--)
    {
        if (a1 <= 0)
        {
            cout << "SW2000";
            return 0;
        }
        if (a2 <= 0)
        {
            cout << "777777777Plus";
            return 0;
        }
        cin >> s1 >> s2;
        if (s1[0] == '7')
        {
            if (s2[0] == 'h')
            {
                if (c1 > 0)c1 -= 100;
                else a1 -= 100;
            }
            else if (s2[0] == 'b')
            {
                if (b1 > 0)b1 -= 30;
                else a1 -= 30;
            }
            else a1 -= 10;
        }
        else
        {
            if (s2[0] == 'h')
            {
                if (c2 > 0)c2 -= 100;
                else a2 -= 100;
            }
            else if (s2[0] == 'b')
            {
                if (b2 > 0)b2 -= 30;
                else a2 -= 30;
            }
            else a2 -= 10;
        }
    }
    if (a1 <= 0)
    {
        cout << "SW2000";
        return 0;
    }
    if (a2 <= 0)
    {
        cout << "777777777Plus";
        return 0;
    }
    return 0;
}

题目详情 - 3 核酸排队 (pintia.cn)

在疫情到来的时候,做核酸成了大多数同学们的日常。做核酸也是需要时间的,而且在一个核酸检测点做核酸的人数往往很多,等待时间有时候会比较长。

在一个核酸检测点基本都安排有两个队列(默认两个队列的长度都为无限大):

  • 扫码队列:在该队列中,我们等待志愿者扫码录入核酸检测信息,志愿者每扫一个同学的码需要x单位时间。
  • 核酸队列:在该队列中,我们等待医生为我们做核酸,每个同学做核酸需要y单位时间。

一位同学做核酸的过程可以认为是先到达扫码队列等待志愿者扫码录入信息,录入信息之后到达核酸队列等待做核酸。一个志愿者一次只能处理一个同学的扫码,一个医生一次只能对一位同学进行核酸检测。

小王深深体会到了医生们的辛苦,他希望通过计算同学们等待做核酸的时间,以此平衡好同学们做核酸、学习和生活的时间。

假设核酸检测点只有一个志愿者和一个医生。已知有n个同学,第i个同学到达核酸检测点(即到达扫码队列)的时间为t**i(数据保证到达扫码队列的时间是升序的,且各不相同),求编程计算第i个同学做核酸耗费的时间w**i

本题认为耗费时间为从到达扫码队列到完成做核酸的时间

输入格式:

一共三行。

第一行为一个整数n(1≤n≤105)。

第二行为两个整数x,y(1≤x,y≤105)

第三行为n个整数t1,t2,t3,…,t**n−1,t**n(1≤t**i≤109)

输出格式:

在一行输出n个核酸检测等待时间w1,w2,w3,…,w**n

输入样例:

3
2 3
3 5 6

输出样例:

在这里给出相应的输出。例如:

5 6 8

问题解析

题目都说了两个队列,那我们就用两个队列来写(滑稽)。

我们用两个队列来存人,一个ma代表在排队扫码的人,一个he代表在做核酸的队列,队列存储的是一个数对,数对的first代表进入队列的时间,second是他在队列等待的时间(初始是0)。我们用一个变量times来表示从第一个人开始扫码的时间,然后随着后面的情况times不断改变。如果times的时间大于当前人到达队列的时间,那么这个差值就是当前人在扫码队列里等待的时间,这个时间还要加上他本人扫码所花时间,然后我们把这个人从扫码队列弹出,并把他放进核酸队列里。如果times小于当前人到达队列的时间,说明这个人一到就开始核酸了,我们直接把times更新到(当前人所到达的时间+他扫码所花时间),而且因为这个人以来就扫上码了,所以他在队里花的时间只有他扫码的时间。

当扫码队列没人了,我们就开始做核酸,方法都和扫码队列一模一样。

(提示:因为一个人到达队列的时间最大可以到1e9,我们最好把变量都开成long long,防止爆了数据白白wa一发)。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    ll n, x, y, a;
    cin >> n >> x >> y;
    queue<PII>ma, he;
    for (int i = 0; i < n; i++)
    {
        cin >> a;
        //前面是到达扫码队列的时间,后面是在扫码队列等待的时间
        ma.push({ a,0 });
    }
    //初始时间和第一个扫码的到达时间一样
    ll times = ma.front().first;
    while (!ma.empty())
    {
        //如果扫码所花时间大于等于当前人到达时间
        if (times >= ma.front().first)
        {
            times += x;
            auto t = ma.front();
            //这是当前人在等待扫码所花时间
            t.second = times - t.first;
            //这是当前人进入核算队列时间
            t.first = times;
            he.push(t);
            ma.pop();
        }
        else
        {
            auto t = ma.front();
            //如果不大于,那么说明当前人一到就扫上码了,花费时间就是扫码时间
            times = t.first + x;
            t.second = x;
            t.first = times;
            he.push(t);
            ma.pop();
        }
    }
    //同上
    times = he.front().first;
    while (!he.empty())
    {
        //如果做核算所花时间大于等于当前人到达时间
        if (times >= he.front().first)
        {
            times += y;
            auto t = he.front();
            he.pop();
            //直接输出他等待的总时间
            cout << t.second + (times - t.first);
            if (!he.empty())cout << " ";
        }
        else
        {
            auto t = he.front();
            he.pop();
            times = t.first + y;
            cout << t.second + y ;
            if (!he.empty())cout << " ";
        }
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值