题意
题目还是简单一点好。
有一张图,每一个点有至少一条出边,每条边上有一个小写字母。有一只大象在图上走路,一开始在 1 1 1 号点,之后每一步会随机选择该点的一条出边并走过去。
将大象走过的边上的小写字母顺次相连,就构成了一个字符串。大象有两个串 a a a 和 b b b,如果大象走出的串包含 a a a 作为子串或包含 b b b 作为子序列,大象就会很生气,停止行走。
大象想知道在停止行走前大象期望会走几步。输入保证这个值是一个有理数,你只要输出它 m o d    998244353 \mod 998244353 mod998244353 的值即可。
对于所有数据, n ≤ 20 , ∣ a ∣ ≤ 10 , ∣ b ∣ ≤ 50 n ≤ 20,|a|≤ 10,|b|≤ 50 n≤20,∣a∣≤10,∣b∣≤50,期望步数是一个确定的有理数。
题解
首先设计 d p dp dp 状态
f i , j , k f_{i,j,k} fi,j,k 表示当前在 i i i 点, a a a 串匹配到了第 j j j 位, b b b 串匹配到了第 k k k 位后还需要走的期望步数
设 v v v 是 i i i 连出的边, d i d_i di 是 i i i 的出度, w w w 是 i i i 到 v v v 边上的字符,则可以得到 f i , j , k = 1 d i ∑ f [ v ] [ n e x [ j ] [ w ] ] [ k + ( b [ k + 1 ] = = w ) ] + 1 f_{i,j,k}=\frac{1}{d_i}\sum f[v][nex[j][w]][k+(b[k+1]==w)]+1 fi,j,k=di1∑f[v][nex[j][w]][k+(b[k+1]==w)]+1 ,可能有环所以应该要高斯消元,这样效率是 O ( ( n × ∣ a ∣ × ∣ b ∣ ) 3 ) O((n \times |a| \times |b|)^3) O((n×∣a∣×∣b∣)3) 过不去,我们需要优化一下
可以发现 f ? , ? , k f_{?,?,k} f?,?,k 只由 f ? , ? , k f_{?,?,k} f?,?,k 和 f ? , ? , k + 1 f_{?,?,k+1} f?,?,k+1 影响,而且有个很显然的结论就是 f ? , ? , ∣ b ∣ = f ? , ∣ a ∣ , ? = 0 f_{?,?,|b|}=f_{?,|a|,?}=0 f?,?,∣b∣=f?,∣a∣,?=0。所以当我们要得到 f ? , ? , k f_{?,?,k} f?,?,k 的答案时,我们只需要将 f ? , ? , k + 1 f_{?,?,k+1} f?,?,k+1 的答案作为其对应常数项,然后在最后一位 = k =k =k 时进行高斯消元即可,复杂度降至 O ( ( n × ∣ a ∣ ) 3 × ∣ b ∣ ) O((n \times |a|)^3 \times |b|) O((n×∣a∣)3×∣b∣),可以过了
懒得 上代码
#include <bits/stdc++.h>
using namespace std;
const int N=55,M=65005,Z=205,P=998244353;
int n,m,d[N],a[N],A,b[N],B,hd[N],W[M],V[M],nx[M],t;
int ne[N][N],id[Z][Z],c,g[Z][Z],f[N][N][N];char sr[N];
int X(int x){if (x>=P) x-=P;if (x<0) x+=P;return x;}
int K(int x,int y){
int z=1;
for (;y;y>>=1,x=1ll*x*x%P)
if (y&1) z=1ll*z*x%P;
return z;
}
void add(int u,int v,int w){
nx[++t]=hd[u];W[t]=w;
V[hd[u]=t]=v;d[u]++;
}
bool J(int x,int y){
for (;x;x--,y--)
if (a[x]!=a[y]) return 0;
return 1;
}
void Gauss(){
for (int v,i=1;i<=c;i++){
if (!g[i][i]){
int k=i;
for (int j=i+1;j<=c;j++)
if (g[j][i]){k=j;break;}
swap(g[i],g[k]);
}
if (!g[i][i]) continue;
v=K(g[i][i],P-2);
for (int j=i;j<=c;j++)
g[i][j]=1ll*g[i][j]*v%P;
g[i][0]=1ll*g[i][0]*v%P;
for (int l,j=1;j<=c;j++)
if (i!=j && g[j][i]){
l=g[j][i];
for (int k=i;k<=c;k++)
g[j][k]=X(g[j][k]-1ll*l*g[i][k]%P);
g[j][0]=X(g[j][0]-1ll*l*g[i][0]%P);
}
}
}
int main(){
scanf("%d%d",&n,&m);;
for (int u,v,i=1;i<=m;i++)
scanf("%d%d%s",&u,&v,sr),
add(u,v,sr[0]-'a');
scanf("%s",sr+1);A=strlen(sr+1);
for (int i=1;i<=A;i++) a[i]=sr[i]-'a';
scanf("%s",sr+1);B=strlen(sr+1);
for (int i=1;i<=B;i++) b[i]=sr[i]-'a';
for (int i=0;i<A;i++)
for (int j=0;j<26;j++)
for (int k=i;~k;k--)
if (a[k+1]==j && J(k,i))
{ne[i][j]=k+1;break;}
for (int i=1;i<=n;i++)
for (int j=0;j<A;j++) id[i][j]=++c;
for (int k=B-1;~k;k--){
for (int i=0;i<=c;i++)
for (int j=0;j<=c;j++) g[i][j]=0;
for (int x,i=1;i<=n;i++)
for (int j=0;j<A;j++)
x=id[i][j],g[x][0]=g[x][x]=d[i];
for (int i=1;i<=n;i++)
for (int y,j=0;j<A;j++){
y=id[i][j];
for (int v,o,x=hd[i];x;x=nx[x]){
v=V[x];o=ne[j][W[x]];
if (W[x]==b[k+1])
g[y][0]=X(g[y][0]+f[v][o][k+1]);
else if (o<A) g[y][id[v][o]]=X(g[y][id[v][o]]-1);
}
}
Gauss();
for (int i=1;i<=n;i++)
for (int j=0;j<A;j++)
f[i][j][k]=g[id[i][j]][0];
}
return printf("%d\n",f[1][0][0]),0;
}