【刷题日记】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;
}
posted @ 2025-10-22 23:39  Alkaid16  阅读(2)  评论(0)    收藏  举报