参考博客:here
题目大意:
给你一个二维矩阵。k个格子上已经填写了字母
X
,
R
,
D
X,R,D
X,R,D代表随便怎么走,向右走,向下走。其他格子随便填。
那么这个矩阵一共有
3
n
m
−
k
3^{nm-k}
3nm−k种可能的填法。每一种填法求出从左上角到右下角行走方案数。问你这所有可能的填法的
f
(
n
,
m
)
f(n,m)
f(n,m)的总和为多少.对
1
e
9
+
7
1e9+7
1e9+7取模.
题目思路:
假设已经画出一条确切路径,那么统计剩下的空格子个数假设为 k k k.那么答案要乘上 3 k 3^k 3k。
但是一条一条求出确切路径,然后统计空格子显然复杂度过不去。还是得考虑在dp的过程中分阶段求出来.
做法:一条路径
(
i
,
j
)
(i,j)
(i,j)向右移动一格时,方案数乘上
3
c
n
t
1
3^{cnt_1}
3cnt1,
c
n
t
1
=
∑
k
=
1
i
−
1
[
(
k
,
j
)
=
=
?
]
cnt_1=\sum_{k=1}^{i-1}[(k,j)==?]
cnt1=∑k=1i−1[(k,j)==?]
一条路径
(
i
,
j
)
(i,j)
(i,j)向下移动一格时,方案数乘上
3
c
n
t
2
3^{cnt_2}
3cnt2,
c
n
t
2
=
∑
k
=
1
j
−
1
[
(
i
,
k
)
=
=
?
]
cnt_2=\sum_{k=1}^{j-1}[(i,k)==?]
cnt2=∑k=1j−1[(i,k)==?]
那么在这个过程中我们就把任意一条路径它之外的所有空格子的个数分阶段计算进入答案里了。
dp采用刷表法即可。
AC代码:来源
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=5e3+5;
const int mod=998244353;
char s[maxm][maxm];
int d[maxm][maxm];
int dn[maxm][maxm];
int rt[maxm][maxm];
int p3[maxm];
int n,m,k;
signed main(){
ios::sync_with_stdio(0);
//init
p3[0]=1;
for(int i=1;i<maxm;i++)p3[i]=p3[i-1]*3%mod;
//
cin>>n>>m>>k;
for(int i=1;i<=k;i++){
int x,y;cin>>x>>y;
char z;cin>>z;
s[x][y]=z;
}
for(int i=1;i<=n;i++){
for(int j=m;j>=1;j--){
rt[i][j]=rt[i][j+1]+(s[i][j]==0);
}
}
for(int j=1;j<=m;j++){
for(int i=n;i>=1;i--){
dn[i][j]=dn[i+1][j]+(s[i][j]==0);
}
}
d[1][1]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if((s[i][j]=='X'||s[i][j]=='D')&&i+1<=n){
d[i+1][j]+=d[i][j]*p3[rt[i][j+1]]%mod;
d[i+1][j]%=mod;
}
if((s[i][j]=='X'||s[i][j]=='R')&&j+1<=m){
d[i][j+1]+=d[i][j]*p3[dn[i+1][j]]%mod;
d[i][j+1]%=mod;
}
if(!s[i][j]){
d[i+1][j]+=2*d[i][j]*p3[rt[i][j+1]]%mod;
d[i+1][j]%=mod;
d[i][j+1]+=2*d[i][j]*p3[dn[i+1][j]]%mod;
d[i][j+1]%=mod;
}
}
}
int ans=d[n][m];
if(s[n][m]==0)ans=ans*3%mod;
cout<<ans<<endl;
return 0;
}