AtCoder题解 —— AtCoder Beginner Contest 183 —— E - Queen on Grid

题目相关

题目链接

AtCoder Beginner Contest 183 E 题,https://atcoder.jp/contests/abc183/tasks/abc183_e

Problem Statement

We have a grid with H horizontal rows and W vertical columns of squares. Square (i,j), which is at the i-th row from the top and j-th column from the left, is wall if Sij is # and road if Sij is ..

There is a queen, the chess piece, at Square (1,1). In one move, it can move any number of squares to the right, downwards, or diagonally to the lower right to a road square without jumping over wall squares.

In how many ways can the queen travel from Square (1,1) to Square (H,W)? Find the count modulo (10^9+7).

Here, two ways to travel are considered different if and only if there exists i such that the position of the queen after the i-th move is different in those two ways.

Input

Input is given from Standard Input in the following format:

H W
S11 ... s1W
.
.
.
SH1 ... SHW

Output

Print the number of ways, modulo (10^9+7), in which the queen can travel from Square (1,1) to Square (H,W).

Samples1

Sample Input 1

3 3
...
.#.
...

Sample Output 1

10

Explaination

There are 10 ways to travel, as follows:

  • (1,1)→(1,2)→(1,3)→(2,3)→(3,3)
  • (1,1)→(1,2)→(1,3)→(3,3)
  • (1,1)→(1,2)→(2,3)→(3,3)
  • (1,1)→(1,3)→(2,3)→(3,3)
  • (1,1)→(1,3)→(3,3)
  • (1,1)→(2,1)→(3,1)→(3,2)→(3,3)
  • (1,1)→(2,1)→(3,1)→(3,3)
  • (1,1)→(2,1)→(3,2)→(3,3)
  • (1,1)→(3,1)→(3,2)→(3,3)
  • (1,1)→(3,1)→(3,3)

Samples2

Sample Input 2

4 4
...#
....
..#.
....

Sample Output 2

84

Explaination

From (1,1), the queen can move to (1,2), (1,3), (2,1), (2,2), (3,1), or (4,1).

One possible path to (4,4) is (1,1)→(3,1)→(3,2)→(4,3)→(4,4).

Samples3

Sample Input 3

8 10
..........
..........
..........
..........
..........
..........
..........
..........

Sample Output 3

13701937

Constraints

  • 2≤H,W≤2000
  • Sij is # or ..
  • S11 and SHW are ..

题解报告

题目翻译

有一个水平 H 行,垂直 W 列的棋盘。坐标 (i, j) 表示从上开始数的第 i 行,从左开始数的第 j 列。如果 Sij 是墙用 # 表示,如果 Sij 是道路用 . 表示。

在坐标 (1, 1) 有一个皇后,每次移动可以向右,向下,从右下对角线移动任意位置,只要道路中没有墙壁。问从 (1, 1) 到 (H, W) 一共右多少种走法,答案对 10^9+7 取模。

题目分析

刚读到这个题目,第一反应使用 BFS 来遍历找出所有的可能。但是仔细考虑后,BFS 一般用来找最短路线,找出所有可能,其实是一个数学题。

根据题目提供的规则,我们可以绘制出皇后的走法

上图中,红色圆圈表示皇后,只要路线上没有墙,她可以向左、向下、右下这三个方向移动任意位置。所以本题如果使用 BFS 来遍历,还真不好写。

由于皇后可以走的方式有三种,我们可以定义三个数组来描述走法,比如用数组 row 表示水平方向走法,col 表示垂直方向走法,dia 表示斜对角线走法。那么 row[i] 表示第 i 行的走法,col[j] 表示第 j 列的走法,斜对角线的计算方法是 i-j,那么会出现负数,数组的下标是不允许出现负数,因此需要增加一个偏移量将负数变为整数,根据本题的数据,最大的偏差是 i=2, j=2000 的时候,也就是 -1998,因此我们可以定义偏移量为 2000。三个数组的定义如下:

const int MAXH=2e3+2;
const int MAXW=2e3+2;
char nums[MAXH][MAXW];//用于保存迷宫

long long row[MAXH];//行走法
long long col[MAXW];//列走法
long long dia[MAXH+MAXW];//对角线

const long long MO=1e9+7;
/*计算对角线的时候 i-j 可能出现负数,最大的负数是 1-2000=-1999,所以需要一个 OFFSET 保证正下标*/
const int OFFSET=max(MAXH, MAXW);//只要超过MAXH和MAXW最大值就可以

根据题目的要求可以知道,(i, j) 如果为 #,说明这里不能走,也就是没有走法,我们设置对应的 row、col、dia 为零。如下

            if ('#'==nums[i][j]) {
                row[i] = 0;
                col[j] = 0;
                dia[i-j+OFFSET] = 0;
            }

(i, j) 如果为 .,说明这里可以走。我们使用样例 1 数据来分析一下,怎么写出走法的递推公式。其实这个递推公式非常容易写,根据走法规则,我们知道要走到 (i, j) 点,我们有三种走法左边向右,上面向下,左上向右下走,因此就是将这三个方向的数据加起来即可。

样例数据 1

根据样例数据 1,我们可以绘制出以下的地图。这里,我们取 OFFSET 为 2002。

坐标 (1, 1),可以走。i=1, j=1,row[1]=1,col[1]=1,dia[2002]=1。因为在起点,我们三个方向的走到 (1,1) 对应的走法都是 1。

坐标 (1, 2),可以走。i=1, j=2,row[1]=2,col[2]=1,dia[2001]=1。

坐标 (1, 3),可以走。i=1, j=3,row[1]=4,col[3]=2,dia[2000]=2。

坐标 (2, 1),可以走。i=2, j=1,row[2]=1,col[1]=2,dia[2003]=1。

坐标 (2, 2),不可以走。i=2, j=2,row[2]=0,col[2]=0,dia[2002]=0。

坐标 (2, 3),可以走。i=2, j=3,row[2]=3,col[3]=5,dia[2001]=4。

坐标 (3, 1),可以走。i=3, j=1,row[3]=2,col[1]=4,dia[2004]=2。

坐标 (3, 2),可以走。i=3, j=2,row[3]=5,col[2]=3,dia[2003]=4。

坐标 (3, 3),可以走。i=3, j=3,row[3]=15,col[3]=15,dia[2002]=10。

本题考点

递推。

AC 参考代码

//https://atcoder.jp/contests/abc183/tasks/abc183_e
//E - Queen on Grid
#include <bits/stdc++.h>

using namespace std;
const int MAXH=2e3+2;
const int MAXW=2e3+2;
char nums[MAXH][MAXW];//用于保存迷宫

long long row[MAXH];//行走法
long long col[MAXW];//列走法
long long dia[MAXH+MAXW];//对角线

const long long MO=1e9+7;
/*计算对角线的时候 i-j 可能出现负数,最大的负数是 1-2000=-1999,所以需要一个 OFFSET 保证正下标*/
const int OFFSET=max(MAXH, MAXW);//只要超过MAXH和MAXW最大值就可以

int main() {
#if 1
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#endif
    int h,w;
    cin>>h>>w;
    for (int i=1; i<=h; i++) {
        for (int j=1; j<=w; j++) {
            cin>>nums[i][j];
        }
    }

    long long ans=-1;
    for (int i=1; i<=h; i++) {
        for (int j=1; j<=w; j++) {
            if ('#'==nums[i][j]) {
                row[i] = 0;
                col[j] = 0;
                dia[i-j+OFFSET] = 0;
            } else {
                long long res = (row[i]+col[j]+dia[i-j+OFFSET])%MO;
                if (1==i && 1==j) {
                    res++;
                }
                ans = res;

                //更新
                row[i] = (row[i]+res)%MO;
                col[j] = (col[j]+res)%MO;
                dia[i-j+OFFSET] = (dia[i-j+OFFSET]+res)%MO;
            }
        }
    }

    cout<<ans<<"\n";

    return 0;
}

上图的两个时间分别是用流式快读和结构化读入。其中 84ms 是快读,64ms 是结构化。

时间复杂度

O(H*W),我们需要遍历所有数据。

空间复杂度

O(H*W),我们需要保存所有数据。

AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道的简要题解: A - Dodecagon 目描述:已知一个正十二边形的边长,求它的面积。 解思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值