#4248. 走
题意
题目还是简单一点好。
有一张图,每一个点有至少一条出边,每条边上有一个小写字母。有一只大象在图上走路,一开始在 $1$ 号点,之后每一步会随机选择该点的一条出边并走过去。
将大象走过的边上的小写字母顺次相连,就构成了一个字符串。大象有两个串 $a$ 和 $b$,如果大象走出的串包含 $a$ 作为子串或包含 $b$ 作为子序列,大象就会很生气,停止行走。
大象想知道在停止行走前大象期望会走几步。输入保证这个值是一个有理数,你只要输出它 $\mod 998244353$ 的值即可。
对于所有数据,$n ≤ 20,|a|≤ 10,|b|≤ 50$,期望步数是一个确定的有理数。
题解
首先设计 $dp$ 状态
$f_{i,j,k}$ 表示当前在 $i$ 点, $a$ 串匹配到了第 $j$ 位, $b$ 串匹配到了第 $k$ 位后还需要走的期望步数
设 $v$ 是 $i$ 连出的边, $d_i$ 是 $i$ 的出度, $w$ 是 $i$ 到 $v$ 边上的字符,则可以得到 $f_{i,j,k}=\frac{1}{d_i}\sum f[v][nex[j][w]][k+(b[k+1]==w)]+1$ ,可能有环所以应该要高斯消元,这样效率是 $O((n \times |a| \times |b|)^3)$ 过不去,我们需要优化一下
可以发现 $f_{?,?,k}$ 只由 $f_{?,?,k}$ 和 $f_{?,?,k+1}$ 影响,而且有个很显然的结论就是 $f_{?,?,|b|}=f_{?,|a|,?}=0$。所以当我们要得到 $f_{?,?,k}$ 的答案时,我们只需要将 $f_{?,?,k+1}$ 的答案作为其对应常数项,然后在最后一位 $=k$ 时进行高斯消元即可,复杂度降至 $O((n \times |a|)^3 \times |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; }