Codeforces 1487B 猫循环:题解|刷题打卡

259 阅读3分钟

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、题目描述:

今天要写的题来自 Codeforces,是一道找规律的思维题。
Codeforces 1487B 猫循环image.png

题目大意: 你有两只猫,一只大猫 AA 和一只小猫 BB,和 nn 个睡觉的位置,AABB 在开始时分别位于 nn11 处,在此后的每个时刻两只猫都会按照以下规则进行移动:

  1. AAnn 开始每次向左移动 11 位,到达位置 11 后会返回 nn 重新开始向左移动。
  2. BB11 开始每次向右移动 11 位,到达位置 nn 后会返回 11 重新开始向右移动。但是如果大猫 AA 位于 x+1x + 1, 小猫 B 位于 x1x - 1, 它们都要移动到 xx,那么小猫 BB 会把位置让给大猫,自己多移动 11 位,也就是 AA 移动到 xx,而 BB 跳到 x+1x + 1 处。

第一行是样例个数 tt,接下来是 tt 行样例,每行都有一个表示位置个数的 nn 和表示时刻的 kk,你需要对每个样例都输出小猫 BB 的位置。

二、思路分析:

这道题最朴素的做法是直接模拟,但是由于数据量很大,所以肯定会超时,所以我们需要观察一下移动的性质。

  1. 如果 nn 为偶数,那么 AABB 永远不会发生碰撞。我们可以考虑最简单的 n=2n = 2 的情形,初始时 BB 位于 11, AA 位于 22, 那下一步 AA 就会移动到 11, 而 BB 则会移动到 22, 后续的移动与此类似,不会发生冲突的可能。很容易就能得到: ans={k%n,k%n0n,k%n=0 ans = \begin{cases} k\,\%\,n,\,k\,\%\,n \neq 0\\ n,\,k\,\%\,n = 0 \end{cases}

  2. 如果 nn 为奇数,直接模拟就复杂一些了,我们可以先试试看。令 n=2m+1n = 2m + 1BB 初始位于 11, AA 初始位于 nn,第一次发生冲突前的时候 BB 位于 mm,而 AA 位于 m+2m + 2, 再移动一次后,BB 位于 m+2m + 2, 而 AA 位于 m+1m + 1。这是第一次发生冲突的情况,而下一次发生冲突的情况很容易就能推出:AA 位于 22,而 BB 位于 nn,它们的下一步都是 11, 再移动一次后 AA 就到了 11, 而 BB 则位于 22。通过比较可以发现:BB11 移动到 mm 所经过的位置是 mm 个,而从 m+2m + 2 移动到 nn 所经过的位置也是 mm 个,也就是说从开始或者刚解决完冲突到再次发生冲突 BB 需要走 mm 步,而每次发生冲突都可以看作是 BB 多走了一步,我们把多走的步数加上,就和第一种情况计算的方式相同了。归纳可得: ans={(k+(k1)/m)%n,(k+(k1)/m)%n0n,k+(k1)/m=0 ans = \begin{cases} (k + \lfloor(k - 1) / m\rfloor)\,\%\,n,\,(k + \lfloor(k - 1) / m\rfloor)\,\%\,n \neq 0\\ n,\,k + \lfloor(k - 1) / m\rfloor = 0 \end{cases}

三、AC 代码:

#include <iostream>
using namespace std;

inline int calc(int n, int k) {
    k %= n;
    return k == 0 ? n : k;
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n, k;
        scanf("%d%d", &n, &k);
        int ans;
        if (n & 1) {
            int m = n / 2;
            k += (k - 1) / m;
        }
        ans = calc(n, k);
        printf("%d\n", ans);
    }
}

四、总结:

这种循环移动的题目考验的是找规律和归纳性质的能力,在平常的刷题过程中我们往往需要利用题目给出的性质化简操作,所以这种思维训练是必不可少的。最后,我们不妨改变题目中的一个条件,如果猫 AA 在到达 11 后不是回到 nn,而是从 11 往右移动,答案会是什么呢?如果 BB 也不会回到 11 重新开始呢?感兴趣的同学可以思考一下。