AC自动机+矩阵快速幂
刚开始是想记f表示走到这的概率,g表示走到这的期望答案。写了一下,数据大概几百万就狂WA不止了,估计是计算量太大掉精度了?
然后发现g实际上没有什么用,用矩阵的一个位置来直接作前缀和就行了。
#include<cstdio>
#include<cstring>
#define S 28
#define L 20
#define N 150
using namespace std;
namespace runzhe2000
{
typedef long double ld;
char s[L];
int n, len, totmen, alpha;
struct matrix
{
ld a[N][N];
matrix operator * (const matrix &that) const
{
matrix r; memset(r.a, 0, sizeof(r.a));
for(int i = 1; i <= totmen; i++)
for(int j = 1; j <= totmen; j++)
for(int k = 1; k <= totmen; k++)
r.a[i][j] += a[i][k] * that.a[k][j];
return r;
}
}A;
struct ACAM
{
ACAM *next[S], *fail;
int ban;
}mem[N], *tot, *null, *root, *q[N];
ACAM *newACAM()
{
ACAM *p = ++tot;
*p = *null; return p;
}
void init()
{
null = tot = mem;
for(int i = 0; i < alpha; i++) null->next[i] = null;
null->fail = null; null->ban = 0;
root = newACAM();
}
void inser(char *s)
{
ACAM *p = root;
for(int i = 0; s[i]; i++)
{
int w = s[i] - 'a';
if(p->next[w] == null) p->next[w] = newACAM();
p = p->next[w];
}
p->ban = 1;
}
void build()
{
root->fail = root; int head = 0, tail = 0;
for(int i = 0; i < alpha; i++)
{
if(root->next[i] == null) root->next[i] = root;
else root->next[i]->fail = root, q[tail++] = root->next[i];
}
for(; head < tail; head++)
{
ACAM *p = q[head];
p->ban |= p->fail->ban;
for(int i = 0; i < alpha; i++)
{
if(p->next[i] == null) p->next[i] = p->fail->next[i];
else p->next[i]->fail = p->fail->next[i], q[tail++] = p->next[i];
}
}
}
void main()
{
scanf("%d%d%d",&n,&len,&alpha);init();
for(int i = 1; i <= n; i++){scanf("%s",s);inser(s);} build();
ACAM *p = mem+1; memset(A.a,0,sizeof(A.a)); ld beta = 1.0/(ld)alpha;
totmen = (tot-mem)<<1 | 1;
for(; ; p++)
{
if(!p->ban)
for(int i = 0; i < alpha; i++)
{
if(p->next[i]->ban)
{
A.a[p-mem][root-mem] += beta;
A.a[p-mem][totmen] += beta;
}
else A.a[p-mem][p->next[i]-mem] += beta;
}
if(p == tot) break;
}
A.a[totmen][totmen] = 1;
matrix r; memset(r.a,0,sizeof(r.a));
for(int i = 1; i <= totmen; i++)
for(int j = 1; j <= totmen; j++)
r.a[i][j] = i==j ? 1 : 0;
for(; len; len >>= 1)
{
if(len & 1) r = r * A;
A = A * A;
}
ld ans = r.a[1][totmen];
printf("%.10lf\n",(double)ans);
}
}
int main()
{
runzhe2000::main();
}