子串的概率

3 篇文章 0 订阅

题目描述
罗老师又在构造字符串了,他有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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值