2012NOIP普及组真题 2. 寻宝

线上OJ:

一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1958

核心思想:(模拟)

1、模拟 每一层从起始房间开始,轮询 x 个有楼梯的房间后到达终点房间
2、由于 0 < N ≤ 10000 , 0 < M ≤ 100 0<N≤10000,0<M≤100 0<N100000<M100 ,如果对每一层楼和每一个房间做暴力,时间复杂度为 O ( 1 0 6 ) O(10^6) O(106),在承受范围之内。
3、但是 每一层楼 轮询的步数 x 可达到1,000,000,远大于 每一层有楼梯的 房间数量

举例:某层有100个房间,但是要逆时针1,000,000次后的房间才是终点房间。但实际只要逆时针100次即可。所以暴力前要 先用 x 对 tot[i] 取模,减少无效暴力

4、初始读入每层楼的每个房间信息时,顺便统计 每层楼有楼梯的房间总数,作为 tot[i]
5、在 模拟时,从起始房间号 [start] 开始,轮询每一个房间如果是有楼梯的房间(读入时用 flag[i][j]=1 标记),则 轮询步数x–当 x 减到 0时,就是终点房间

题解代码:
#include <bits/stdc++.h>
#define MOD 20123
using namespace std;

const int N = 10005, M = 105;

int n, m, start, ans;  // start 存储进入每一层的起始房间号,第0层时为读入
int flag[N][M], x[N][M];  // flag[i][j]=1: 1有楼梯,0无楼梯
int tot[N] = {0}; // tot[i] 记录第i+1层有楼梯房间的数量

// 由于 0<x≤1,000,000,远大于每一层有楼梯的房间数量 tot[i],所以暴力前要先用x对 tot[i] 取模,减少无效暴力
int main()
{
    scanf("%d%d", &n, &m);
  
    int ans = 0;
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < m; j ++ )
        {
            scanf("%d%d", &flag[i][j], &x[i][j]);
            if(flag[i][j])  tot[i]++;
        }

    cin >> start;
    for(int i = 0; i < n; i ++ )
    {
        int num = x[i][start];  // 取每一层起始房间内的数字作为步数
        ans = (ans + num) % MOD;// 先记录答案,再取模

        num %= tot[i]; // 步数对当前楼层有梯子的房间数量取模(切忌,先更新ans,再对tot[i]取模。否则ans就错了)
        if (num == 0)  num = tot[i];// 注意边界,如果取模后为0,说明步数是tot[i]的整数倍。所以只走一次tot[i]即可

        int j = start; // 从起点房间开始
        while(1)
        {
            if(flag[i][j] == 1) // 如果该房间有楼梯
            {
                num--;          // 剩余步数-1
                if(num == 0)    // 如果减完后剩余步数为0
                {
                    start = j;  // 则j房间就是这一层的终点房间,也是下一层的起点房间
                    break;
                }
            }
            j = (j + 1) % m;  // 如果还没有跳出这一层,则j++, 继续搜索下一个房间。直至跳出本层的while循环
        }

    }

    cout << ans << endl;
    return 0;
}
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值