洛谷题解P1563 玩具谜题
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;
}
本文欢迎转载,转载时请注明本文链接


浙公网安备 33010602011771号