好像是(SDOI2017)某题的数据范围弱化版
不过把这道题放到(SDOI2017)某题应该有(60)可以拿吧
看到多串首先建(AC)自动机
之后就可以视为把这个随机生成的字符串放到(AC)机上匹配,由于是随机生成,那么本质上就是在(AC)机上随机游走,走到有结束标记的点就停下来
设(dp[i])表示(i)点经过的期望次数,由于终点走到就停下了,所以终点的期望等价于概率
非常显然我们可以列出这样的方程
[dp_v=sum_{e(u,v)in G}dp_u imes w(u,v)
]
(w(u,v))就是走这条边的概率
但是(0)号节点是特殊的,因为这个节点是起点,期望次数应该加(1)
也就是
[dp_0=1+sum_{e(u,0)in G}dp_u imes w(u,v)
]
之后就会发现这样的方程根本没有办法来推,因为(AC)机根本就不是一个拓扑结构
所以我们把这些方程一个一个列出来,之后高斯消元来求出每一个(dp)的值
复杂度(O(n^3m^3))
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
#define eps 1e-6
#define re register
#define maxn 205
#define LL long long
#define inf 999999999
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
inline int check(double a) {if(std::fabs(a)<eps) return 1;return 0;}
int n,m,len,cnt;
char S[maxn];
double P[maxn];
double a[maxn][maxn],ans[maxn],dp[maxn];
int son[maxn][26],fail[maxn],f[maxn];
inline void ins(int o)
{
int now=0;
for(re int i=1;i<=len;i++)
{
if(!son[now][S[i]-'A']) son[now][S[i]-'A']=++cnt;
now=son[now][S[i]-'A'];
}
f[now]=o;
}
inline void build()
{
std::queue<int> q;
for(re int i=0;i<m;i++) if(son[0][i]) q.push(son[0][i]);
while(!q.empty())
{
int k=q.front();q.pop();
for(re int i=0;i<m;i++)
if(son[k][i]) fail[son[k][i]]=son[fail[k]][i],q.push(son[k][i]);
else son[k][i]=son[fail[k]][i];
}
}
int main()
{
n=read(),len=read(),m=read();
int p,q;
for(re int i=0;i<m;i++)
p=read(),q=read(),P[i]=double(p)/double(q);
for(re int i=1;i<=n;i++) scanf("%s",S+1),ins(i);
build();
for(re int i=0;i<=cnt;i++)
{
if(f[i]) continue;
for(re int j=0;j<m;j++)
a[son[i][j]][i]+=P[j];
}
for(re int i=0;i<=cnt;i++)a[i][i]+=-1;
a[0][cnt+1]=-1.0;
for(re int i=0;i<=cnt;i++)
{
int now=i;
for(re int j=i+1;j<=cnt;j++) if(std::fabs(a[j][i])>std::fabs(a[now][i])) now=j;
std::swap(a[now],a[i]);
for(re int j=cnt+1;j>=i;--j)
a[i][j]/=a[i][i];
for(re int j=i+1;j<=cnt;j++)
for(re int k=cnt+1;k>=i;--k)
a[j][k]-=a[j][i]*a[i][k];
}
ans[cnt]=a[cnt][cnt+1];
for(re int i=cnt-1;i>=0;i--)
{
ans[i]=a[i][cnt+1];
for(re int j=i+1;j<=cnt;j++)
ans[i]-=a[i][j]*ans[j];
}
for(re int i=0;i<=cnt;i++) dp[f[i]]=ans[i];
for(re int i=1;i<=n;i++)
{
if(check(dp[i])) puts("0.00");
else printf("%.2lf
",dp[i]);
}
return 0;
}