玩具谜题

NOIP2016d1t1。

原题链接:https://www.luogu.org/problem/show?pid=1563#sub

一道送分(命 题。

不过,方向感不强的同学(比如说我)刚开始做这道题的时候就会感到懵逼。

时过一年,在考场懵逼的我,现在再拿起这道题写,脑子里有时也是一个大写的懵逼。

怎么办?找规律。

小人的“左”和“右”都是相对方向,相对于其脸朝外还是朝里。在考场上,我的想法是写四个if,然后模拟找的过程。

可惜当时因为调不出来,心里略有紧张,最后炸了。

今天,我的想法也是这样,但我发现了一个规律。

小人的初始朝向dir只有0和1,0朝里,1朝外,转向时候输入的dir,0表示相对向左,1表示相对向右。

这样应该是有四个组合:(0,0)、(0,1)、(1,0)和(1,1)。不过,它可以被简化成两个情况。

接下来的讨论如果方向感不强可能会懵逼。为了说明方便,我规定一个正方向:沿着输入的表向下的方向为正方向。

简化成的情况就只有两个方向,一个是我个人定义的正方向,另一个就是个人定义反方向(也就是沿着输入表向上数)。

不要被题目上所说的给出的逆时针顺序迷惑,这里不讨论顺逆时针的问题,只讨论我个人定义的方向。

也就是说,各位在看我这篇题解的时候,就不要想顺逆时针了,那样想多了会晕,亲测。

为了方便,我简称正方向和反方向。

这道题的规定,反方向数到表头的时候,从表尾继续;正方向数到表尾的时候,从表头继续。

这两句加粗的话将是下面讨论的基础。

对于组合(0,0),代表朝里向左数,换到自定义方向就是反方向。

对于组合(0,1),代表朝里向右数,换到自定义方向就是正方向。

对于组合(1,0),代表朝外向左数,换到自定义方向就是正方向。

对于组合(1,1),代表朝外向右数,换到自定义方向就是反方向。

不理解这四句话请和图片对照一下,正确性显然。

发现什么规律了吗?正方向的组合,两数之和为1,反方向的组合,两数之和为0或2。

那么我们开一个临时变量t,t代表小人初始方向参数值和当前转向参数值之和,根据上面的结论,只会有0,1,2三种结果。而其中,0和2代表的是同一种结果。

想到什么?对2取模!

对2取模得到的结果只有0和1,正好对应反方向和正方向。

那就好办了。如果是正方向,求出当前位置+偏移数量的值,再对n取模,就是下一个位置。

如果是反方向,那就求出当前位置-偏移数量的值,等等,这有可能会变成负的,那再加一个n就好。仍然是再对n取模得到位置。

最后得到一个位置,输出那个位置的名字就好。

附参考代码:

 1 #include <iostream>
 2 #include <string>
 3 #define maxn 100005
 4 using namespace std;
 5 struct peo{
 6     int dir;
 7     string nm;
 8 };
 9 peo a[maxn];
10 int n,m;
11 int dir,s;
12 int now = 0;
13 int main(){
14     ios::sync_with_stdio(false);
15     cin >> n >> m;
16     for (register int i=0;i<n;i++)
17         cin >> a[i].dir >> a[i].nm;
18 
19     for (int i=1;i<=m;i++){
20         cin >> dir >> s;
21         int t = a[now].dir + dir;
22         if (t % 2 == 0)
23             now = (now - s + n) % n;
24         else
25             now = (now + s) % n;     
26     }
27     cout << a[now].nm << endl;
28     return 0;
29 }
原文地址:https://www.cnblogs.com/OIerShawnZhou/p/7471230.html