CodeForces - 1247E Rock Is Push【線性DP】

題目鏈接:https://codeforces.com/problemset/problem/1247/E

題意:一個n*m的矩陣,有個別位置會有小球,小球受到撞擊會沿着方向撞到牆爲止(每個小球會佔一個格子)。你從左上角出發,只能向右或者向下走,問你走到右下角的方案數。

思路:首先我們定義我們的狀態f[i][j][0] 表示在(i, j) 這個位置向右走的方案數,f[i][j][1] 表示在(i, j) 這個位置向下走的方案數。

先考慮向右走,如果s[i][j] == '.' 的話,f[i][j][0] = f[i][j - 1][0] + f[i][j - 1][1] 而如果s[i][j] == 'R' 的話(假設現在就這一個球),那麼實際上是到達不了(i, m) 這個位置的,但是由於我們的狀態沒有考慮當前有球的情況,所以我們需要減去f[i][m][1](1是因爲存在經過(i,m)向下走的方案),具體的球數我們可以預處理算出來,向下走同理。

但是我們正常從左上推導到右下是不行的,因爲在減去的時侯的狀態方案數我們還沒有計算出來,所以我們就倒着推導計算是一樣的。

目標狀態:f[n][m][0] + f[n][m][1]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn= 2e3 + 10;
const int mod = 1e9 + 7;
char s[maxn][maxn];
ll f[maxn][maxn][2], d[maxn][maxn][2]; //0表示向右走,1表示向下走

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
    if(s[n][m] == 'R') printf("0\n");
    else if(n == 1 && m == 1) printf("1\n");
    else
    {
        for(int i = n; i >= 1; --i) //統計行列石頭數
        {
            for(int j = m; j >= 1; --j)
            {
                d[i][j][0] = d[i][j + 1][0] + (s[i][j] == 'R'); //行
                d[i][j][1] = d[i + 1][j][1] + (s[i][j] == 'R'); //列
            }
        }
        for(int i = 1; i < n; ++i) if(!d[i][m][1]) f[i][m][1] = 1;
        for(int i = 1; i < m; ++i) if(!d[n][i][0]) f[n][i][0] = 1;
        for(int i = n - 1; i > 0; --i)
        {
            for(int j = m - 1; j > 0; --j)
            {
                f[i][j][0] = (f[i][j + 1][0] + f[i][j + 1][1]) % mod;
                if(s[i][j + 1] == 'R') f[i][j][0] = (f[i][j][0] - f[i][m - d[i][j + 1][0] + 1][1] + mod) % mod;
                f[i][j][1] = (f[i + 1][j][0] + f[i + 1][j][1]) % mod;
                if(s[i + 1][j] == 'R') f[i][j][1] = (f[i][j][1] - f[n - d[i + 1][j][1] + 1][j][0] + mod) % mod;
            }
        }
        printf("%lld\n", (f[1][1][1] + f[1][1][0]) % mod);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章