将自动机建出来之后就可以得到一个转移矩阵,在没有两个串不能重叠的条件下直接跑矩乘就可以了。但是现在有这个条件,我们就新加一个点表示转移到的单词节点会转移到这里面去,然后这个点连出的边只有自己且边权为1。还要注意的是,一个节点的fail点是单词节点的话那么这个点也要标记成单词节点(终态),因为他是禁位,也要转移到那个新点。
#include <bits/stdc++.h>
#define rep(i,a,b) for (int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for (int i = a , _ = b ; i >= _ ; i --)
#define For(i,a,b) for (int i = a , _ = b ; i < _ ; i ++)
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
const int maxn = 207;
typedef int arr[maxn];
arr val , fail;
int n , len , m , tot;
int go[maxn][27];
char str[maxn];
inline void ins(char*s , int id) {
int u = 1;
for (char *_ = s + 1 ; *_ ; _ ++) {
int c = *_ - 'a';
if (!go[u][c]) go[u][c] = ++ tot;
u = go[u][c];
}
val[u] = 1;
}
void input() {
n = rd() , len = rd() , m = rd() , tot = 1;
rep (i , 1 , n) scanf("%s" , str + 1) , ins(str , i);
}
std::queue<int> Q;
inline void build() {
For (c , 0 , m) {
int u = go[1][c];
if (!u) go[1][c] = 1;
else Q.push(u) , fail[u] = 1;
}
while (!Q.empty()) {
int u = Q.front() ; Q.pop();
For (c , 0 , m) {
int v = go[u][c] , f = go[fail[u]][c];
if (!v) {
go[u][c] = f;
continue;
}
Q.push(v);
fail[v] = f , val[v] |= val[f];
}
}
}
struct matrix {
long double a[maxn][maxn];
matrix() { memset(a , 0 , sizeof a); }
inline long double* operator[](int x) {
return a[x];
}
inline void clear() {
rep (i , 0 , tot) rep (j , 0 , tot) a[i][j] = 0;
}
inline void operator=(matrix &t) {
rep (i , 0 , tot) rep (j , 0 , tot) a[i][j] = t[i][j];
}
inline void print() {
rep (i , 0 , tot) rep (j , 0 , tot) printf("%.2Lf%c" , a[i][j] , j == tot ? '\n' : ' ');
puts("==========");
}
friend inline void operator*= (matrix&a , matrix&b) {
matrix c ; c.clear();
rep (i , 0 , tot) rep (j , 0 , tot) rep (k , 0 , tot)
c[i][j] += a[i][k] * b[k][j];
a = c;
}
}A , B;
inline void Pow() {
B = A , A.clear();
rep (i , 0 , tot) A[i][i] = 1;
while (len) {
if (len & 1) A *= B;
B *= B , len >>= 1;
}
}
void solve() {
build();
long double pp = 1.0 / m;
rep (i , 1 , tot) For (c , 0 , m) if (val[go[i][c]])
A[i][0] += pp , A[i][1] += pp;
else
A[i][go[i][c]] += pp;
A[0][0] = 1;
// A.print();
Pow();
printf("%.6Lf\n" , A[1][0]);
// A.print();
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
input();
solve();
return 0;
}