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 }