洛谷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 imes 10^2 imes 10^4 = 10^{12} ]

是会超时的。

优化:

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

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

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

比如,我当前在第 (i) 层的第 (p) 个房间,上面写着数字 (8) —— 也就是说我要找到第 (8) 把钥匙对应的房间,同时 (sum[i]=3),所以我饶了一圈之后回到第 (p) 个房间,我还剩下 (8-3=5) 把钥匙;我饶了两圈之后回到第 (p) 个房间,我还剩下 (5-3=2) 把钥匙。所以这跟我一开始就找 (8 ext{ 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;
}
原文地址:https://www.cnblogs.com/quanjun/p/12698163.html