题目描述
罗老师又在构造字符串了,他有n个字母库(这些字母都是小写字母),每个字母都有被选用的概率(他们的概率之和为1)。他想使用这些字母组成一个长度为m的字符串S,那么这个字符串的各种组成形式都有一定的概率。
这样漫无目的的构造字符串很无聊,所以罗老师就想,再给定一个字符串T,他想知道T是S子串的概率有多少?
输入
第一行输入n, m
接下来n行,每行输入一个小写字母及其被选概率
最后一行输入字符串T
输出
输出T是S子串的概率(写成百分比形式,保留2位小数)
样例输入
4 10
w 0.25
o 0.25
r 0.25
d 0.25
word
样例输出
2.73%
提示
【样例说明】
其他样例1:
2 10
a 1.0
b 0.0
abc
输出:
0.00%
其他样例2:
2 100
a 0.312345
b 0.687655
abab
输出:
98.54%
【数据规模和约定】
1<=n<=26 1<=m<=1000
题解
给你将n个字母打出来的概率,让你求打出一个字符串长度为m的串,其中串s为它的子串的概率。
先特判不可能组成的,再就是dp[i][j],第一维i代表当前达到了第i个字符,第二维代表当前到达了s串的第j个字符。
当打出下一个字符为s[j + 1],是状态转移为dp[i + 1][j + 1] = dp[i][j] * p;当打出下一个字符不是j + 1时,找到它的next数组中的值,即kmp算法,如果找到一个当前串的最大的相等的前后缀,状态转移为dp[i + 1][id + 1] = dp[i][j] * p;如果get_next的返回值为0,需要判断当前字符是否与s串的第一个相等如果相等,状态转移为dp[i + 1][1] = dp[i][j] * p;否则,状态转移为dp[i + 1][0] = dp[i][j] * p。
代码
#include<bits/stdc++.h>
#define mod 1000000009
#define inf 10000000
#define N 1000105
#define pa pair<long long,int>
typedef long long ll;
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,len;
double p[27],dp[1005][1005],ans;
char s[1005],ch[1005],S[1005];
int Next[1005];
void KMP()
{
Next[0]=-1;
for (int i=2;i<=len;i++)
{
int k=i-1;
while (s[Next[k]+1]!=s[i]&&k) k=Next[k];
Next[i]=Next[k]+1;
}
Next[0]=0;
}
int main()
{
n=read();m=read();
for (int i=1;i<=n;i++)
{
scanf("%s%lf",S,&p[i]);
ch[i]=S[0];
}
scanf("%s",s+1);
len=strlen(s+1);
KMP();
dp[0][0]=1;
for (int i=0;i<m;i++)
for (int j=0;j<len;j++)
for (int x=1;x<=n;x++)
if (ch[x]==s[j+1]) dp[i+1][j+1]+=dp[i][j]*p[x];
else
{
int k=j;
while (Next[k]&&s[Next[k]+1]!=ch[x]) k=Next[k];
if (s[Next[k]+1]==ch[x]) k=Next[k]+1;
else k=0;
dp[i+1][k]+=dp[i][j]*p[x];
}
for (int i=1;i<=m;i++) ans+=dp[i][len];
ans*=100.0;
printf("%.2lf%%",ans);
return 0;
}