Description
Input
Output
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]]]);
}