Update
2020.11.24 对全文进行了重构与优化。
原题传送门
Description
有 (n) 个玩具小人围成一圈, 已知它们的职业和朝向。现在第 (1) 个玩具小人告诉小南一个包含 (m) 条指令的谜題, 其中第 (z)条指令形如 “左数/右数第 (s) 个玩具小人”。你需要输出依次数完这些指令后,到达的玩具小人的职业。
现在给定玩具小人的个数 (n) ,指令的条数 (m),每个玩具小人的朝向和职业(其中 (0) 表示朝向圈内,(1) 表示朝向圈外)。 再依次给出 (m) 条指令,包含包含两个整数 (a_i),(s_i), (a_i=0),表示向左数 (s_i)个人;若 (a_i=1),表示向右数 (s_i) 个人。
说明 :
「朝向」共分两种,一种为朝向圈内,一种为朝向圈外。
示意如下 :
面朝圈内的玩具小人, 它的左边是顺时针方向, 右边是逆时针方向。
面向圈外的玩具小人, 它的左边是逆时针方向, 右边是顺时针方向。
保证 :
- 表示朝向的数字不会出现其他的数。
- 表示职业的字符串长度不超过 (10) 且仅由小写字母构成,字符串不为空,并且字符串两两不同。
- 表示指令执行方向的数字(即 (a_i))不会出现其他的数。
Solution
首先考虑到最后输出的是名字,因为名字和朝向是紧密相连的,所以说可以用一个 struct
来捆绑起来。
考虑到结构体之后,思路已经很明了了,在每次循环的时候用一个变量 pos
来记录当前的位置,根据 (a_i) 和 (s_i) 进行变化。
对于位置的改变,可以分为以下四种情况 :
- 当前位置的小人面朝圈内,要向左移动。
- 当前位置的小人面朝圈内,要向右移动。
- 当前位置的小人面朝圈外,要向左移动。
- 当前位置的小人面朝圈外,要向右移动。
根据 Description 中提到的方向,
面朝圈内的玩具小人, 它的左边是顺时针方向, 右边是逆时针方向。
面向圈外的玩具小人, 它的左边是逆时针方向, 右边是顺时针方向。
可以推导出以下变化的公式 : (按照上述顺序)
pos=(pos+n-s)%n;
pos=(pos+s)%n;
pos=(pos+s)%n;
pos=(pos+n-s)%n;
最后输出即可。
Code
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
struct Node{
bool toward;
string name;
}map[100001];
inline void read(int &x){
int f=1;
char ch=getchar();
x=0;
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
int n,m;
int main(){
read(n);read(m);
for(int i=0;i<n;i++) cin>>map[i].toward>>map[i].name; //下面的取模操作的pos结果在[0,n]之间,所以必须从0读入。
int pos=0; //同上,从0开始
int a,b;
for(int i=1;i<=m;i++){
cin>>a>>b;
if(map[pos].toward==0&&a==0) pos=(pos+n-b)%n;
else if(map[pos].toward==0&&a==1) pos=(pos+b)%n;
else if(map[pos].toward==1&&a==0) pos=(pos+b)%n;
else if(map[pos].toward==1&&a==1) pos=(pos+n-b)%n;
}
cout<<map[pos].name;
return 0;
}