dtoj#4248. 走
题目描述:
题目还是简单一点好。
有一张图,每一个点有至少一条出边,每条边上有一个小写字母。有一只大象在图上走路,一开始 在 $1$ 号点,之后每一步会随机选择该点的一条出边并走过去。
将大象走过的边上的小写字母顺次相连,就构成了一个字符串。大象有两个串 $a$ 和 $b$,如果大象走 出的串包含 $a$ 作为 子串或包含 $b$ 作为子序列,大象就会很生气,停止行走。
大象想知道在停止行走前大象期望会走几步。输入保证这个值是一个有理数,你只要输出它 $\mod 998244353$ 的值即可。
思路:
对于会有正推会有无穷无尽的局面的概率期望问题,大多列出等式消元求解。
考虑 $f[x][j][k]$ 表示在点 $x$ 上,当前走过的字符匹配到 $a$ 串比配到 $j$ ,匹配 $b$ 串匹配到 $k$ 的走过的步数的期望。
有一个发现是答案在 $ f[?][?][|b|] $ 时答案为 $0$ ,可以考虑根据这个列出一个方程式,高斯消元,但是效率是 $O((abn)^{3})$
但是我们发现最后一位一定是递增的,所以考虑每次制作 $k,k+1$ 的方程式,并高斯消元,最后答案是 $f[1][0][0]$ 。
转移式:
$$
f[x][j][k]=\sum ((f[to[i]][ne[j][w[i]]][k/k+1]+1)\times \frac{1}{out[x]})
$$
$ne[j][ch]$ 是提前预处理出对于 $a$ 串,如果匹配到第 $j$ 位下一位是 $ch$ ,那么下一次可以匹配到哪里。
如果走过的边上的字符恰好满足为 $b[k+1]$ 时, 对应最后一维为 $k+1$ 的 $f$ 数组,即增加一个常数。
否则则对左边对应项的系数造成改变。
以下代码:
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=25,M=1e4+5,p=998244353; char s[55]; int a[12],b[55],l1,l2,A[205][205],ne[N][28],f[N][12][55]; int n,m,head[N],nex[M],to[M],cnt,w[M],out[N],id[N][12]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il void insert(int x,int y,int z){ nex[++cnt]=head[x];head[x]=cnt; to[cnt]=y;w[cnt]=z;out[x]++; } il int mu(int x,int y){ return x+y>=p?x+y-p:x+y; } il int ksm(LL a,int y){ LL b=1; while(y){ if(y&1)b=b*a%p; a=a*a%p;y>>=1; } return b; } il bool pd(int x,int y){ if(x==y)return 1;if(x==0)return 1; for(;x;x--,y--){ if(a[x]!=a[y])return 0; } return 1; } il void Gauss(int n){ for(int i=1,inv;i<=n;i++){ if(!A[i][i]){ int mx=i; for(int j=i+1;j<=n;j++)if(A[j][i]>A[mx][i])mx=j; if(i^mx)for(int j=0;j<=n;j++)swap(A[i][j],A[mx][j]); } if(!A[i][i])continue;inv=ksm(A[i][i],p-2); A[i][i]=1;A[i][0]=1ll*A[i][0]*inv%p; for(int j=i+1;j<=n;j++)A[i][j]=1ll*A[i][j]*inv%p; for(int j=1;j<=n;j++){ if(i^j&&A[j][i]){ int g=A[j][i];A[j][0]=mu(A[j][0],p-1ll*g*A[i][0]%p); for(int k=i;k<=n;k++)A[j][k]=mu(A[j][k],p-1ll*g*A[i][k]%p); } } } } int main() { n=read();m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read();scanf(" %s",s); insert(x,y,s[0]-'a'); } scanf(" %s",s+1);l1=strlen(s+1); for(int i=1;i<=l1;i++)a[i]=s[i]-'a'; scanf(" %s",s+1);l2=strlen(s+1); for(int i=1;i<=l2;i++)b[i]=s[i]-'a'; for(int i=0;i<l1;i++)for(int j=0;j<26;j++) for(int k=i;k>=0;k--)if(a[k+1]==j&&pd(k,i)){ ne[i][j]=k+1;break; } int tot=0; for(int i=1;i<=n;i++)for(int j=0;j<l1;j++)id[i][j]=++tot; for(int l=l2-1,x;l>=0;l--){ for(int i=1;i<=n;i++)for(int j=0;j<l1;j++) x=id[i][j],A[x][0]=A[x][x]=out[i]; for(int i=1;i<=n;i++)for(int j=0;j<l1;j++){ x=id[i][j]; for(int k=head[i];k;k=nex[k]){ int v=to[k],lj=ne[j][w[k]],lk=l+(w[k]==b[l+1]); if(w[k]==b[l+1]||lj==l1) A[x][0]=mu(A[x][0],f[v][lj][lk]); else A[x][id[v][lj]]=mu(A[x][id[v][lj]],p-1); } } Gauss(tot); for(int i=1;i<=n;i++)for(int j=0;j<l1;j++)f[i][j][l]=A[id[i][j]][0]; for(int i=0;i<=tot;i++)for(int j=0;j<=tot;j++)A[i][j]=0; } printf("%d\n",f[1][0][0]); return 0; }