Description
【JZOJ B组】下蛋爷_题解【JZOJ B组】下蛋爷_题解_02
【JZOJ B组】下蛋爷_C_03
Input
【JZOJ B组】下蛋爷_题解_04

Output
【JZOJ B组】下蛋爷_C_05

Sample Input
5
he
she
her
hers
his
hershe
0.30 5

Sample Output
0.163 0.031 0.031 0.031 0.002

Data Constraint

Hint
出现的次数分别为:
2 1 1 1 0
由概率的知识可以得到输出

       he    she   her   hers  his

一次之后 1.000 1.000 1.000 1.000 0.300
又一次之后 1.000 0.510 0.510 0.510 0.090
又一次之后 0.657 0.216 0.216 0.216 0.027
又一次之后 0.348 0.084 0.084 0.084 0.008
又一次之后 0.163 0.031 0.031 0.031 0.002

思路

先用 AC 自动机找出所有串出现的次数,排序然后由概率知识递推一下就可以了。
现在把所有出现次数相同的点看成一个点
设 f[i][j]表示前 i 轮选择忘记 j 次的概率
则 f[i][j]=f[i-1][j-1]*(1-p)+f[i-1][j]*p
设答案数组 ans[]
ans[i]=f[k][1]+f[k][2]+f[k][3]+……+f[k][i-1]

代码

#include<cstdio>
#include<cstring>
using namespace std;
const int M=277;
double f[M],g[M],pp;
int fail[M*20],d[M*20],t[20*M][27],a[20*M][20*M],sum[M],h[1000010];

void makefail()
{	
    int h=0,x,y,z,tail=1;
	d[1]=1;
    while(h<tail)
    {
        x=d[++h];
        for (int i=1; i<=26; i++)
        if(t[x][i])
        {
            y=t[x][i],z=fail[x];
            while(z && !t[z][i]) z=fail[z];
            fail[y]=t[z][i];
            d[++tail]=y;
            if (!fail[y])fail[y]=1;
        }
    }
}
int main()
{
	int n,tot=1,p,m;
	scanf("%d\n",&n);
	char s[30];
    for (int i=1; i<=n; i++)
    {
        scanf("%s\n",s+1);
        p=1,m=strlen(s+1);
        for (int j=1; j<=m; j++)
        {
            if(!t[p][s[j]-96]) t[p][s[j]-96]=++tot;
            p=t[p][s[j]-96];
        }
        t[p][0]++;
		a[p][++a[p][0]]=i;
    }
	makefail();
	char st[1000010];
    scanf("%s\n",st+1);
    m=strlen(st+1);
    for(int i=1,x=1,j=st[i]-96; i<=m; j=st[++i]-96)
    {
        while(x!=1 && !t[x][j]) x=fail[x];
        if(t[x][j]) x=t[x][j];
        for(int y=x;y!=1;y=fail[y])
        for(int i=1; i<=a[y][0]; i++)sum[a[y][i]]++;
    }
	for (int i=1; i<=n; i++)h[sum[i]]=1;
	scanf("%lf%d",&pp,&tot);f[0]=pp;f[1]=1-pp;
	for (int i=2; i<=n; i++)g[i]=1;
	g[1]=pp;
	for (int i=2; i<=tot; i++)
	{
		for (int j=1; j<=n; j++)g[j]=g[j-1]+f[j-1]*pp+f[j-2]*(1-pp);
		for (int j=n; j>0; j--)f[j]=f[j-1]*(1-pp)+f[j]*pp;
		f[0]=g[1];
	}
	for (int i=0,j=1; j<=n && i<=1000000; j++)
	{
		while (!h[i] && i<=1000000)i++;
		h[i++]=j;
	}
	for (int i=1; i<=n; i++)printf("%.3lf ",g[h[sum[i]]]);
}