恶补了一下AC自动机,花了一天时间终于全部搞明白了。
思路:将每个人的串加入AC自动机,在AC自动机生成的状态图上建边,注意单词末尾的节点只能转移到自己概率为1,
然后将矩阵自乘几十次后误差就很小了, 或者可以高斯消元搞出精确解。
#include<bits/stdc++.h> #define LL long long #define ll long long #define fi first #define se second #define mk make_pair #define pii pair<int, int> #define y1 skldjfskldjg #define y2 skldfjsklejg using namespace std; const int N = 100 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; int n, l, m, pos[11]; double pro[11]; char s[11]; struct Matrix { int r, c; double a[101][101]; Matrix(int r = 0, int c = 0) { this->r = r; this->c = c; memset(a, 0, sizeof(a)); } Matrix operator * (const Matrix &B) const { Matrix C(r, c); for(int i = 0; i < r; i++) for(int j = 0; j < c; j++) for(int k = 0; k < r; k++) C.a[i][j] += a[i][k] * B.a[k][j]; return C; } }; struct Ac { int val[N], ch[N][26], f[N], last[N], cnt, SZ; void init(int SZ = 26) { cnt = 0; this->SZ = SZ; for(int c = 0; c < SZ; c++) ch[0][c] = 0; } int getId(char c) { return c - 'A'; } int newNode() { cnt++; memset(ch[cnt], 0, sizeof(ch[cnt])); val[cnt] = f[cnt] = last[cnt] = 0; return cnt; } void add(char *s, int &pos) { int u = 0; for(int i = 0; s[i]; i++) { int c = getId(s[i]); if(!ch[u][c]) ch[u][c] = newNode(); u = ch[u][c]; } val[u]++; pos = u; } void build() { queue<int> que; f[0] = 0; for(int c = 0; c < SZ; c++) { if(!ch[0][c]) continue; f[ch[0][c]] = last[ch[0][c]] = 0; que.push(ch[0][c]); } while(!que.empty()) { int u = que.front(); que.pop(); for(int c = 0; c < SZ; c++) { int v = ch[u][c]; if(!v) { ch[u][c] = ch[f[u]][c]; continue; } else { que.push(v); f[v] = ch[f[u]][c]; last[v] = val[f[v]] ? f[v] : last[f[v]]; } } } } void buildMatrix(Matrix &A) { for(int u = 0; u <= cnt; u++) { if(val[u]) A.a[u][u] = 1; else { for(int c = 0; c < m; c++) { int v = ch[u][c]; A.a[u][v] += pro[c]; } } } } } ac; int main() { scanf("%d%d%d", &n, &l, &m); for(int i = 0; i < m; i++) { double p, q; scanf("%lf%lf", &p, &q); pro[i] = p / q; } ac.init(m); for(int i = 1; i <= n; i++) { scanf("%s", s); ac.add(s, pos[i]); } ac.build(); Matrix A(ac.cnt + 1, ac.cnt + 1); ac.buildMatrix(A); for(int i = 1; i <= 40; i++) A = A * A; for(int i = 1; i <= n; i++) printf("%.2f\n", A.a[0][pos[i]]); return 0; } /* */