洛谷P1076 寻宝 题解 模拟

题目链接:https://www.luogu.com.cn/problem/P1076

解题思路:
这道题目是一道标准的模拟题。一开始我们在第 \(1\) 层的 \(p\) 号房间,然后我们要沿着逆时针方向找 \(x\) 把钥匙,然后进入上一层。

我们可以暴力模拟一下这个算法,看看在最坏情况下的的时间复杂度。

如下所述是我能够想到的最坏情况:

\(N = 10000\) 层,每层楼有 \(M = 100\) 个房间,每一层我都要寻找 \(x = 1,000,000\) 把钥匙,每一层只有一把钥匙。

这种情况下,我要转 \(10^6\) 圈才能收集 \(x\) 把钥匙,每一圈我遍历了 \(M=100\) 个房间,再算上层数 \(N=10^4\),总的时间复杂度达到了

\[10^6 \times 10^2 \times 10^4 = 10^{12} \]

是会超时的。

优化:

我可以开一个 \(sum[]\) 数组,其中 \(sum[i]\) 用于记录第 \(i\) 层的房间总共有多少把钥匙。

然后,我假设我刚进入第 \(i\) 层的时候在第 \(p\) 号房间,嫔妾房间上写的号码是 \(x\),那么:

  • 如果 \(x\) 不能被 \(sum[i]\) 整除,则我们只需要从 \(p\) 开始逆时针找到第 \(x \text{ mod } sum[i]\) 把钥匙就可以了(这里 \(\text{mod}\) 表示取余数);
  • 否则(\(x\) 能被 \(sum[i]\) 整除),则我们只需要从 \(p\) 的前一个房间按照顺时针顺序找到第一把有钥匙的房间就可以了。

比如,我当前在第 \(i\) 层的第 \(p\) 个房间,上面写着数字 \(8\) —— 也就是说我要找到第 \(8\) 把钥匙对应的房间,同时 \(sum[i]=3\),所以我饶了一圈之后回到第 \(p\) 个房间,我还剩下 \(8-3=5\) 把钥匙;我饶了两圈之后回到第 \(p\) 个房间,我还剩下 \(5-3=2\) 把钥匙。所以这跟我一开始就找 \(8 \text{ mod } 3 = 2\) 把钥匙是一样的效果。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
int has[10010][110], num[10010][110], sum[10010], n, m, p, ans;
const int MOD = 20123;
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i ++) {
        for (int j = 0; j < m; j ++) {
            cin >> has[i][j] >> num[i][j];
            sum[i] += has[i][j];
        }
    }
    cin >> p;
    for (int i = 0; i < n; i ++) {
        int val = num[i][p] % sum[i];
        ans = (ans + num[i][p]) % MOD;
        if (val) { // 如果不能整除,从p开始逆时针找第 val%sum[i]把钥匙
            while (true) {
                if (has[i][p]) {
                    val --;
                    if (!val) break;
                    p = (p+1) % m;
                }
                else {
                    p = (p+1) % m;
                }
            }
        }
        else {  // 如果能整除,从p-1开始顺时针找第一把钥匙
            while (true) {
                p = (p+m-1) % m;
                if (has[i][p]) break;
            }
        }
    }
    cout << ans << endl;
    return 0;
}
posted @ 2020-04-14 15:08  quanjun  阅读(262)  评论(0编辑  收藏  举报