洛谷题解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;
}
原文地址:https://www.cnblogs.com/-pwl/p/13736713.html