【刷题日记】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号
浙公网安备 33010602011771号