目录
1 时空密接
在抗击疫情的过程中,我们需要清楚确定密接,而感染者的整个运动过程中和他位置重合的人都将被当作密切接触者,现在就请你设计一个算法计算两个人的轨迹是否有时空密接。
为了简化问题我们把场景当成一个二维坐标系,每个人看作坐标系上的一个整数点,在每一个时刻会原地不动或向上下左右移动一格,我们认为两个人只要在某一时刻出现在了同一个网格中就是时空密接。
输入格式:
第一行包含五个用空格隔开的正整数x1,y1,x2,y2(−1e9≤x1,y1,x2,y2≤1e9),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时刻在同一位置,属于时空密接。
思路:
模拟,可用坐标偏移量来简化代码,具体实现如下
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
using namespace std;
typedef pair<int,int> PII;
const int N = 2010;
int n, m;
string s1, s2;
map<char, pair<int, int>> mp;
// 偏移量简化代码
void init()
{
// 第一个数表示x, 第二个数表示y
// x 不变,y 向上走一格
mp['W'] = {0, 1};
// x 不变,y 向下走一格
mp['S'] = {0, -1};
// x 向左走一格,y 不变
mp['A'] = {-1, 0};
// x 向右走一格,y 不变
mp['D'] = {1, 0};
// x 不变,y 不变
mp['O'] = {0, 0};
}
int main()
{
init();
int x1, y1, x2, y2, t;
scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &t);
cin >> s1;
cin >> s2;
for(int i = 0; i < t; i ++ )
{
if(x1 == x2 && y1 == y2)
{
puts("yes");
return 0;
}
x1 += mp[s1[i]].first, y1 += mp[s1[i]].second;
x2 += mp[s2[i]].first, y2 += mp[s2[i]].second;
}
if(x1 == x2 && y1 == y2)
{
puts("yes");
return 0;
}
puts("no");
return 0;
}
2 今晚吃鸡
777777777Plus和SW2000正在游玩一款fps(第一人称射击类)游戏,在游戏中777777777Plus和SW2000需要瞄准射击,当系统判定到击中头部,身体,和四肢时会造成不同的伤害。当击中头部时,会造成100点伤害;当击中胸背部时,会造成30点伤害,当击中四肢时,会造成10点伤害。当血量小于等于0时,游戏结束,血量不为0的一方获胜。
同时该游戏有防具设计,包括头盔(保护头部)和护甲(保护胸背部)。当玩家穿着防具时,对该部位的攻击会由扣除血量改为扣除防具的耐久度。当防具耐久度降低到0时将会破碎失去伤害抵挡效果。
换言之,如果防具当前耐久为x,收到的攻击为y,当x>y时,防具的耐久变为x−y,不会破碎。当x≤y时,防具会破碎,且此次攻击不再扣除玩家血量。
现在,给出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
正常思路:
可利用二维数组简化代码,a[0]表示 777777777Plus 的信息,a[1]表示 SW2000 的信息,将 四肢的护甲值变成为 0 ,进一步减少特判情况,进而再次减少代码长度。
大神思路:
最后受一个攻击的人必是失败者,直接判断最后一种情况,输出结果即可
正常思路超短代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
using namespace std;
typedef pair<int,int> PII;
const int N = 2010;
int n, m;
string s1, s2;
map<string, int> mp;
void init()
{
mp["head"] = 100;
mp["body"] = 30;
mp["limbs"] = 10;
}
int main()
{
// 初始化,减少代码长度
init();
int a[2][4];
for(int i = 0; i < 3; i ++ ) scanf("%d", &a[0][i]);
for(int i = 0; i < 3; i ++ ) scanf("%d", &a[1][i]);
a[0][3] = -1, a[1][3] = -1;
int n;
scanf("%d", &n);
while(n -- )
{
string name, s;
cin >> name >> s;
// 判断人
int i, j;
if(name == "777777777Plus") i = 0;
else i = 1;
// 判断受伤部位
if(s == "head") j = 2;
else if(s == "body") j = 1;
else j = 3;
// 计算
if(a[i][j] > 0) a[i][j] -= mp[s];
else a[i][0] -= mp[s];
}
if(a[0][0] <= 0) puts("SW2000");
if(a[1][0]<= 0) puts("777777777Plus");
return 0;
}
3 核酸排队
在疫情到来的时候,做核酸成了大多数同学们的日常。做核酸也是需要时间的,而且在一个核酸检测点做核酸的人数往往很多,等待时间有时候会比较长。
在一个核酸检测点基本都安排有两个队列(默认两个队列的长度都为无限大):
- 扫码队列:在该队列中,我们等待志愿者扫码录入核酸检测信息,志愿者每扫一个同学的码需要x单位时间。
- 核酸队列:在该队列中,我们等待医生为我们做核酸,每个同学做核酸需要y单位时间。
一位同学做核酸的过程可以认为是先到达扫码队列等待志愿者扫码录入信息,录入信息之后到达核酸队列等待做核酸。一个志愿者一次只能处理一个同学的扫码,一个医生一次只能对一位同学进行核酸检测。
小王深深体会到了医生们的辛苦,他希望通过计算同学们等待做核酸的时间,以此平衡好同学们做核酸、学习和生活的时间。
假设核酸检测点只有一个志愿者和一个医生。已知有n个同学,第i个同学到达核酸检测点(即到达扫码队列)的时间为ti(数据保证到达扫码队列的时间是升序的,且各不相同),求编程计算第i个同学做核酸耗费的时间wi。
本题认为耗费时间为从到达扫码队列到完成做核酸的时间。
输入格式:
一共三行。
第一行为一个整数n(1≤n≤105)。
第二行为两个整数x,y(1≤x,y≤105)
第三行为n个整数t1,t2,t3,...,tn−1,tn(1≤ti≤109)
输出格式:
在一行输出n个核酸检测等待时间w1,w2,w3,...,wn
输入样例:
3
2 3
3 5 6
输出样例:
在这里给出相应的输出。例如:
5 6 8
思路一(正常思路):
开两个数组,分别保存排队和做核酸时需要等待的时间,然后输出即可,注意用数据很大用long long。
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 1e5+10;
int n, m;
int x, y;
int main()
{
scanf("%d", &n);
scanf("%d %d", &x, &y);
LL t1 = 0, t2 = 0;
LL dd[N] = {0}, dh[N] = {0};
for(int i = 0; i < n; i ++ )
{
LL k;
scanf("%lld", &k);
// 此人排队的开始时间为此人到达的时间 k
if(k >= t1)
{
dd[i] = x;
t1 = k + x;
}
else
{
dd[i] = (t1 - k) + x;
t1 = t1 + x;
}
// 此人核酸的开始时间为此人排完队的时间 tt
LL tt = t1;
if(tt >= t2)
{
dh[i] = y;
t2 = tt + y;
}
else
{
dh[i] = (t2 - tt) + y;
t2 = t2 + y;
}
}
for(int i = 0; i < n; i ++ )
{
if(i) printf(" ");
printf("%lld", dd[i] + dh[i]);
}
puts("");
return 0;
}
思路二(简单思路):
本次消耗时间 :做完核酸的时间 - 刚排队的时间,
本次刚排队的时间为,max(上一个人排完队的时间,此次到达时间) + x;
做完核酸的时间为,max(上一个人做完核酸的的时间与,本次的人到达做核酸的时间) + y;
所以等待时间此次为做完核酸的时间减去刚到达的时间。
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 1e5+10;
int n, m;
int x, y;
int main()
{
scanf("%d", &n);
scanf("%d %d", &x, &y);
LL t1 = 0, t2 = 0, k;
for(int i = 0; i < n; i ++ )
{
if(i) printf(" ");
scanf("%lld", &k);
t1 = max(t1 + x, k + x);
t2 = max(t1 + y, t2 + y);
printf("%lld", t2 - k);
}
return 0;
}