【刷题日记】Robot on Grid(网格DP)
题目链接
题目大意
给定 $ h \times w $的矩阵,其中 $ k $ 个位置已经被填字母,剩余位置仍待填。字母可以填 $ D, R, X $,分别代表位于该格子只能向下走、只能向右走、两个方向都可以走。求在剩余所有 $ 3 ^ {h w - k} $ 种填字母方案中,从 $ (1, 1) $ 走向 $ (h, w) $ 的路径数之和。
其中 $ 1 \le h \le 5000 , 1 \le w \le 5000 $。答案对 $ 998244353 $ 取模。
测试样例
输入1
2 2 3
1 1 X
2 1 R
2 2 R
输出1
5
样例解释
只有右上角的格子没有被填字母。
当填 $ R $ 时,有一条路径。
当填 $ D $ 时,有两条路径。
当填 $ X $ 时,有两条路径。
一共五条路径。
输入2
3 3 5
2 3 D
1 3 D
2 1 D
1 2 X
3 1 R
输出2
150
输入3
5000 5000 10
585 1323 R
2633 3788 X
1222 4989 D
1456 4841 X
2115 3191 R
2120 4450 X
4325 2864 X
222 3205 D
2134 2388 X
2262 3565 R
输出3
139923295
题解
思路
动态规划。 $ dp_{i, j} $ 表示走到 $ (i, j) $ 的路径数。现在考虑计算所有方案的总路径数。假设走到该格子经过了 $ n $ 个未填字母的方块。每个未填字母的方块有 $ 3 $ 种填法,其中一定有且仅有两条满足需要的走法,而路径外面的 $ k - n $ 个未填字母方块可以任意填,所以答案需要乘以 $ 2 ^ n \times 3 ^ {k - n} $, 我们可以让 $ dp $ 在代码中乘以 $ 3 ^ k $ 进行预处理,随后每次遇到空方块,都乘以 $ \frac{2}{3} $ 。
AC代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const i64 MOD = 998244353;
i64 h, w, k, hh, ww, dp[5010][5010];
char mp[5010][5010], c;
i64 inv3;
i64 pow_mod(i64 a, i64 b){
i64 res = 1;
while(b){
if(b % 2)
res = (res * a) % MOD;
a = (a * a) % MOD;
b /= 2;
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> h >> w >> k;
for(i64 i = 1;i<=h;i++)
for(i64 j = 1;j<=w;j++)
mp[i][j] = '?';
for(i64 i = 1;i<=k;i++){
cin >> hh >> ww >> c;
mp[hh][ww] = c;
}
inv3 = pow_mod(3LL, MOD-2);
dp[1][1] = pow_mod(3LL, h * w - k);
for(i64 i = 1;i<=h;i++)
for(i64 j = 1;j<=w;j++){
if(i == 1 && j == 1)
continue;
if(i > 1){
if(mp[i-1][j] == '?')
dp[i][j] += (dp[i-1][j] * inv3 % MOD) * 2 % MOD;
else if(mp[i-1][j] != 'R')
dp[i][j] += dp[i-1][j];
dp[i][j] %= MOD;
}
if(j > 1){
if(mp[i][j-1] == '?')
dp[i][j] += (dp[i][j-1] * inv3 % MOD) * 2 % MOD;
else if(mp[i][j-1] != 'D')
dp[i][j] += dp[i][j-1];
dp[i][j] %= MOD;
}
}
cout << dp[h][w];
return 0;
}

浙公网安备 33010602011771号