zoukankan      html  css  js  c++  java
  • [CodeForces

    [CodeForces - 1225E]Rock Is Push 【dp】【前缀和】

    标签:题解 codeforces题解 dp 前缀和


    题目描述

    Time limit
    2000 ms
    Memory limit
    524288 kB
    Source
    Technocup 2020 - Elimination Round 2
    Tags
    binary search dp *2200
    Site
    https://codeforces.com/problemset/problem/1225/E

    题面

    火狐截图_2019-12-24T07-30-34.370Z.png

    Example
    Input1

    1 1
    .

    Output1

    1

    Input2

    2 3
    ...
    ..R

    Output2

    0

    Input3

    4 4
    ...R
    .RR.
    .RR.
    R...

    Output3

    4

    题目大意

    给定(n, m),和一张长宽分别为(n,m)的地图。(cdot)代表可以通过,(R)代表岩石,无法通过。一个人从左上((1,1))出发,想要到达右下((n, m)),他每步只能向下或向右走一格。其间他可以推动与他相邻的一连串岩石一格,根据他从上一步到达这格的方向,但不能将岩石推出地图。问一共有多少条不同的走法?

    例如,
    (n = 4, m = 4),地图为

    [cdot cdot cdot R \ cdot R R cdot \ cdot R R cdot \ R cdot cdot cdot \ ]

    有如下四条路径,用(PushD)代表向下推岩石,用(PushR)代表向右推岩石:

    1. ((1,1) o (2,1) o(3,1) o PushR o(3,2) o(4,2) o(4,3) o(4,4))
    2. ((1,1) o(2,1) o PushR o(2,2) o PushD o(3,2) o PushR o(3,3) o (4,3) o (4,4))
    3. ((1,1) o(1,2) o PushD o(2,2) o PushR o(2,3) o PushD o(3,3) o (3,4) o (4,4))
    4. ((1,1) o(1,2) o (1,3) o PushD o(2,3) o (2,4) o (3,4) o (4,4))

    解析

    • 询问从((1,1))走到((n, m))的路径条数,我们也可以反过考虑从((n, m))走到((1,1))的路径条数。

    • 我们令(dpR[i][j])表示从((i,j))的右边一格即从((i, j + 1))到达((i,j))的路径条数,令(dpD[i][j])表示从((i,j))的下边一格即从((i + 1, j))到达((i,j))的路径条数。令(kD, kR)分别为从((i,j))到此列最下端和此行最右端的岩石总数。因为岩石可以向右推至地图边缘,所以我们易得$$dpD[i][j] = sum_{t=i + 1}^{n - kD}dpR[t][j].$$将此列中行坐标在区间([i+1, n-kD])的全部能从右边到达的路径条数都加入(dpD[i][j])中。
      新建 PPTX 演示文稿_04.png

      计算(dpD)示意图

      同理,我们可得$$dpR[i][j] = sum_{t=j + 1}^{m - kR}dpD[i][t].$$

    • 为了得到每点的(kR,kD),我们需要分别预处理一下每行每列从右至左,从下至上的岩石数量的前缀和。
      ((i,j))以右(包括((i,j)))的全部岩石数量:(numR[i][j] = numR[i][j + 1] + (s[i][j] == \,'R'))
      ((i,j))以下(包括((i,j)))的全部岩石数量:(numD[i][j] = numD[i + 1][j] + (s[i][j] == \,'R'))

    新建 PPTX 演示文稿_03.png

    计算岩石总数前缀和

    • 看到如上的累加公式,我们很容易想到要用前缀和来处理。否则时间复杂度会升到立方。
      我们令$$ sumD[i][j] = sumD[i][j + 1] + dpD[i][j], sumR[i][j] = sumR[i + 1][j] + dpR[i][j].$$
      则原公式可优化为$$egin{cases}dpD[n][m] = dpR[n][m] = 1, dpD[i][j] = sum_{t=i + 1}^{n - numD[i][j]}dpR[t][j] = sumR[i + 1][j] - sumR[n - numD[i][j] + 1][j], dpR[i][j]= sum_{t=j + 1}^{m - numR[i][j]}dpD[i][t] = sumD[i][j + 1] - sumD[i][m - numR[i][j] + 1] end{cases}.$$

    • 最后答案即为(dpD[1][1] + dpR[1][1]),注意随时取模。

    • 存在两种情况需要特判,详见代码。



    以第三个样例为例试举两例,
    新建 PPTX 演示文稿_01.png

    计算(2,1)的(dpD)(dpR)

    新建 PPTX 演示文稿_02.png
    计算(1,1)的(dpD)(dpR)


    通过代码

    /*
    Status
    	Accepted
    Time
    	108ms
    Memory
    	102804kB
    Length
    	1284
    Lang
    	GNU G++11 5.1.0
    Submitted
    	2019-12-23 18:13:00
    RemoteRunId
    	67463663
    */
    
    #include <bits/stdc++.h>
    using namespace std;
    
    const int MOD = 1e9 + 7;      //随时取模.
    const int MAXN = 2e3 + 50;
    
    char s[MAXN][MAXN];
    int  numD[MAXN][MAXN], numR[MAXN][MAXN], sumD[MAXN][MAXN], sumR[MAXN][MAXN], dpD[MAXN][MAXN], dpR[MAXN][MAXN];
    int n, m;
    
    int main()
    {
        scanf("%d%d", &n, &m);
    
        for(int i = 1; i <= n; i ++)
            scanf("%s", s[i] + 1);
    
        if(s[1][1] == 'R' || s[n][m] == 'R'){        //第一种特判情况,起点或终点被岩石占上,则没有路径可以到达.
            printf("0");
            return 0;
        }
    
        if(n == 1 && m == 1){                       //第二种特判情况,地图大小为1*1,则直接输出1.
            printf("1");
            return 0;
        }
    
        for(int i = n; i >= 1; i --){              //从右下开始预处理岩石总数前缀和.
            for(int j = m; j >= 1; j --){
                numD[i][j] = numD[i + 1][j] + (s[i][j] == 'R');
                numR[i][j] = numR[i][j + 1] + (s[i][j] == 'R');
            }
        }
    
    
        sumD[n][m] = sumR[n][m] = dpD[n][m] = dpR[n][m] = 1;
        for(int i = n; i >= 1; i --){                   //从右下开始状态转移.
            for(int j = m; j >= 1; j --){                               
             if(i == n && j == m)   continue;
            dpD[i][j] = (sumR[i + 1][j] - sumR[n - numD[i + 1][j] + 1][j]) % MOD;
            dpR[i][j] = (sumD[i][j + 1] - sumD[i][m - numR[i][j + 1] + 1]) % MOD;
            
            sumD[i][j] = (sumD[i][j + 1] + dpD[i][j]) % MOD;
            sumR[i][j] = (sumR[i + 1][j] + dpR[i][j]) % MOD;
            }
        }
    
        printf("%d", (dpR[1][1] + dpD[1][1] + 2ll * MOD) % MOD);            //得出答案.
        return 0;
    }
    
    
    

  • 相关阅读:
    教程:在 Visual Studio 中开始使用 Flask Web 框架
    教程:Visual Studio 中的 Django Web 框架入门
    vs2017下发现解决python运行出现‘No module named "XXX""的解决办法
    《sqlite权威指南》读书笔记 (一)
    SQL Server手工插入标识列
    hdu 3729 I'm Telling the Truth 二分图匹配
    HDU 3065 AC自动机 裸题
    hdu 3720 Arranging Your Team 枚举
    virtualbox 虚拟3台虚拟机搭建hadoop集群
    sqlserver 数据行统计,秒查语句
  • 原文地址:https://www.cnblogs.com/satchelpp/p/12091865.html
Copyright © 2011-2022 走看看