洛谷P4356[CERC2015]Looping Labyrinth代码(讲解会在以后博客上发布,敬请谅解)

[CERC2015] Looping Labyrinth - 洛谷

# [CERC2015] Looping Labyrinth

## 题面翻译

一个$n×m$的矩形,其中每格为路或墙,通过将图案平移来获得迷宫。迷宫是一个大小有限的坐标系,其图案在四个方向上重复。

用整数(包括负整数)表示横纵坐标。向下行数增加,向右列数增加,坐标$(0,0)$处称为原点。特别地,图案的左上角在原点,而右下角在坐标$(n-1,m-1)$。

原点是出口,为了从开始逃离迷宫,我们要从不同的起点到达原点,每一步可向上,下,左或右。对于每个起点,确定是否可以逃离迷宫。

输入格式:

第一行包含两个整数$n$和$m$($1≤n$,$m≤100$)。

以下每一行包含$m$个字符。“#”表示墙,“.”表示路。
以下的一行包含整数$q$($1≤q≤200000$)表示起点的数量。

以下$q$行每行包含两个整数$r$和$c$($-10^9≤r$,$c≤10^9$),表示每个起点的坐标。

保证原点和所有起点为路。

输出格式:
输出$q$行。如果可以从当前起点逃出迷宫,则每行输出$yes$,否则输出$no$。

## 题目描述

A labyrinth is obtained by tiling the entire plane with a pattern – a rectangular grid consisting of n rows and m columns where every cell is either empty or blocked. The result is an infinite grid of cells with the pattern repeating in all four directions. 

Formally, suppose we denote both rows and columns of the infinite grid with integers (including the negative integers). The row number increases as we move downwards in the grid, while the column number increases as we go to the right. The cell at coordinates (0,0) is called the origin. The labyrinth is obtained by copying the pattern (without mirroring or rotation) to every n-by-m rectangular area that, in the upper-left corner, has a cell with the row number divisible by n and the column number divisible by m. In particular, the upper-left corner of the pattern gets copied to the origin, while the lower-right corner gets copied to the cell with coordinates (n−1,m−1). 

To escape the labyrinth starting from a particular cell, we need to reach the origin via a sequence of empty cells, going up, down, left or right in each step. 

You are given a pattern and a sequence of possible starting cells. For each starting cell determine if it is possible to escape the labyrinth.

## 输入格式

The first line contains two integers n and m (1≤n, m≤100)–the number of rows and columns in the pattern, respectively. Each of the following n lines contains a string of exactly m characters describing one row of the pattern. The character # denotes a blocked cell while the dot character denotes an empty cell. The following line contains an integer q (1≤q≤200,000) – the number of starting cells. The k-th of the following q lines contains two integers r and c ($−10^9$ ≤ r, c ≤ $10^9$) – the row and column of the k-th starting cell. 

The origin and all starting cells will be empty.

## 输出格式

Output should consist of q lines. The k-th line should contain the word yes if it is possible to exit the labyrinth from the k-th starting cell and the word no otherwise.

## 样例 #1

### 样例输入 #1

```
6 9 
..#####.. 
..#...#.. 
......#.. 
..#####.. 
..#...... 
..#...#.. 

1 4 
5 4 
1 -5 
5 -5 
-1000000000 0
```

### 样例输出 #1

```
yes 
no 
no 
yes 
yes
```

## 提示

Central Europe Regional Contest 2015 Problem L

题意翻译

一个n×mn×m的矩形,其中每格为路或墙,通过将图案平移来获得迷宫。迷宫是一个大小有限的坐标系,其图案在四个方向上重复。

用整数(包括负整数)表示横纵坐标。向下行数增加,向右列数增加,坐标(0,0)(0,0)处称为原点。特别地,图案的左上角在原点,而右下角在坐标(n−1,m−1)(n−1,m−1)。

原点是出口,为了从开始逃离迷宫,我们要从不同的起点到达原点,每一步可向上,下,左或右。对于每个起点,确定是否可以逃离迷宫。

输入格式:

第一行包含两个整数nn和mm(1≤n1≤n,m≤100m≤100)。

以下每一行包含mm个字符。“#”表示墙,“.”表示路。 以下的一行包含整数qq(1≤q≤2000001≤q≤200000)表示起点的数量。

以下qq行每行包含两个整数rr和cc(−109≤r−109≤r,c≤109c≤109),表示每个起点的坐标。

保证原点和所有起点为路。

输出格式: 输出qq行。如果可以从当前起点逃出迷宫,则每行输出yes,否则输出no。

题解如下(讲解会发布在以后的博客里):

#include<bits/stdc++.h>
using namespace std;
int n, m;
bool H[105][105];
struct node {
    int xB, yB, xI, yI;
};
node calc(int x, int y) {
    node ans;
    ans.xB = x >= 0 ? (x / n) : ((x + 1) / n - 1);
    ans.yB = y >= 0 ? (y / m) : ((y + 1) / m - 1);
    ans.xI = x - ans.xB * n; assert(ans.xI >= 0 && ans.xI < n);
    ans.yI = y - ans.yB * m;
    return ans;
}
int U = 0, V = 0;
void insert(int nU, int nV) {
    if (U == -998244353) return; // case 2
    if (nU == 0 && nV == 0) return; // meaningless
    if (nU < 0) nU = -nU, nV = -nV;
    else if (nU == 0 && nV < 0) nV = -nV;
    int g = __gcd(nU, abs(nV)); nU /= g, nV /= g;
    if (nU == U && nV == V) return;
    if (U || V)  U = V = -998244353; // case 1 -> case 2
    else U = nU, V = nV; // case 0 -> case 1
}
bool vis[105][105];
pair<int, int> pB[105][105];
bool isvalid(node u) {
    if (H[u.xI][u.yI]) return 0;
    if (!vis[u.xI][u.yI]) {
        vis[u.xI][u.yI] = 1;
        pB[u.xI][u.yI] = make_pair(u.xB, u.yB);
        return 1;
    }
    insert(u.xB - pB[u.xI][u.yI].first, u.yB - pB[u.xI][u.yI].second);
    return 0;
}
int d[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        char c = getchar();
        while (c != '.' && c != '#') c = getchar();
        for (int j = 0; j < m; j++)
            H[i][j] = c == '#', c = getchar();
    }

    queue<pair<int, int> > Q;
    isvalid((node){0, 0, 0, 0}); Q.push(make_pair(0, 0));
    while (!Q.empty()) {
        pair<int, int> u = Q.front(); Q.pop();
        for (int i = 0; i < 4; i++) {
            int vx = u.first + d[i][0], vy = u.second + d[i][1];
            if (isvalid(calc(vx, vy))) Q.push(make_pair(vx, vy));
        }
    }

    int T; scanf("%d", &T);
    while (T--) {
        int x, y; scanf("%d%d", &x, &y);
        node qaq = calc(x, y);
        if (!vis[qaq.xI][qaq.yI]) { printf("no\n"); continue; }
        if (U == 0 && V == 0) {
            if (qaq.xB != pB[qaq.xI][qaq.yI].first || qaq.yB != pB[qaq.xI][qaq.yI].second)
                printf("no\n");
            else printf("yes\n");
            continue;
        }
        if (U == -998244353 && V == -998244353) {
            printf("yes\n"); continue;
        }
        int nU = qaq.xB - pB[qaq.xI][qaq.yI].first,
            nV = qaq.yB - pB[qaq.xI][qaq.yI].second;
        if (nU == 0 && nV == 0) { printf("yes\n"); continue; }
        if (nU < 0) nU = -nU, nV = -nV;
        else if (nU == 0 && nV < 0) nV = -nV;
        int g = __gcd(nU, abs(nV)); nU /= g, nV /= g;
        if (nU == U && nV == V) { printf("yes\n"); continue; }
        printf("no\n");
    }
}

希望能给予各位更多的帮助,谢谢大家的支持!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值