题目链接:点击打开链接
思路:
用d[i][j]表示前i个字符,已经匹配了字母中的j个字符,最终包含这个字母的概率。
每次转移的时候有n个方向, 表示第i个字符选哪个字符, 那么有个问题, 如果我当前选的这个字符失配了, 那么转移之后我还匹配了多少个字符。 这恰恰是KMP能做的。
细节参见代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <stack> #include <bitset> #include <cstdlib> #include <cmath> #include <set> #include <list> #include <deque> #include <map> #include <queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; typedef long double ld; const double eps = 1e-6; const double PI = acos(-1); const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; const int seed = 131; const ll INF64 = ll(1e18); const int maxn = 1000 + 10; int n, m, vis[maxn][13], kase = 0, len, f[13]; double d[maxn][13]; struct node { char c; double p; }a[100]; char p[13]; void getfail() { f[0] = 0; f[1] = 0; for(int i = 1; i < len; i++) { int j = f[i]; while(j && p[i] != p[j]) j = f[j]; f[i+1] = p[i] == p[j] ? j+1 : 0; } } double dp(int i, int j) { double& ans = d[i][j]; if(i == m) return 0; if(vis[i][j] == kase) return ans; vis[i][j] = kase; ans = 0; for(int k = 1; k <= n; k++) { int cur = j; while(cur && p[cur] != a[k].c) cur = f[cur]; if(p[cur] == a[k].c) { if(cur >= len-1) ans += a[k].p; else ans += dp(i+1, cur+1)*a[k].p; } else ans += dp(i+1, cur) * a[k].p; } return ans; } int main() { while(~scanf("%d%d", &n, &m)) { if(n == 0 && m == 0) return 0; for(int i = 1; i <= n; i++) { scanf("%s%lf", p, &a[i].p); a[i].c = p[0]; } scanf("%s", p); len = strlen(p); getfail(); ++kase; double ans = dp(0, 0) * 100; ans *= 100; double cur = round(ans); printf("%.2f%%\n", (double)cur/100.0); } return 0; }
时间: 2024-10-18 20:59:17