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
Solution
这题有点强行二合一的意思
首先求出每个字符串出现的次数,可以用KMP,不过会被卡常
用AC自动机速度快的飞起
AC自动机的简单讲解点这里
第二部分就是求概率
因为出现次数相同的单词要么全部记住,要么全部忘掉,所以可以当做一个
想自己推概率的不要看下面
用
f[i][j]
表示出现次数从小到大的第
i
个单词,第
这个概率可以分为两部分
一是
j−1
这个时刻,
i−1
这个单词还记着,那么j时刻i这个单词不可能忘,因为需要一个时刻来忘掉
i−1
这个单词,概率为
f[i−1][j−1]∗1
二是
j−1
或之前的时刻,
i−1
这个单词就已经被忘了,那么
j
时刻
总的概率为
f[i][j]=f[i−1][j−1]∗1+(f[i−1][j]−f[i−1][j−1])∗p
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 210
#define db double
using namespace std;
int n,t[N*10][27],tot=1,a[N*21][N],fail[N*21],d[N*21],up[N*21];
db b1[1010],b2[1010],ans[N];
char s[1000010];
struct node{
int x,y;
}c[N];
void makefail()
{
int h=0,w=1;d[1]=1;
while(h<w)
{
int x=d[++h];
fo(i,1,26)
if(t[x][i]!=0)
{
int y=t[x][i],z=fail[x];
while(z!=0&&t[z][i]==0) z=fail[z];
fail[y]=t[z][i];
d[++w]=y;
fail[y]=fail[y]==0?1:fail[y];
up[y]=y;
if(t[y][0]==0&&up[y]!=1) up[y]=up[fail[y]];
}
}
}
void query(int m)
{
int x=1;
fo(i,1,m)
{
int j=s[i]-96;
while(x!=1&&t[x][j]==0) x=fail[x];
if(t[x][j]) x=t[x][j];
for(int y=up[x];y;y=up[fail[y]])
fo(i,1,a[y][0]) c[a[y][i]].x++;
}
}
bool cnt(node x,node y){return x.x<y.x;}
int main()
{
scanf("%d\n",&n);
fo(i,1,n)
{
scanf("%s\n",s+1);
int x=1,m=strlen(s+1);
fo(j,1,m)
{
if(t[x][s[j]-96]==0) t[x][s[j]-96]=++tot;
x=t[x][s[j]-96];
}
t[x][0]++;a[x][++a[x][0]]=i;
}
makefail();
scanf("%s\n",s+1);
int m=strlen(s+1);
query(m);
fo(i,1,n) c[i].y=i;
sort(c+1,c+n+1,cnt);
c[0].x=-1;
db p;int l;
scanf("%lf %d",&p,&l);
fo(j,0,l) b1[j]=0;
fo(i,1,n)
{
b2[0]=1;
if(c[i].x==c[i-1].x) {ans[c[i].y]=ans[c[i-1].y];continue;}
fo(j,1,l)
{
b2[j]=b1[j-1]+(b2[j-1]-b1[j-1])*p;
}
fo(j,1,l) b1[j]=b2[j];b1[0]=1;
ans[c[i].y]=b2[l];
}
fo(i,1,n) printf("%.3lf ",ans[i]);
}