【NOIP2017模拟6.26】下蛋爷

55 篇文章 0 订阅
44 篇文章 0 订阅

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局还记住的概率是多少
这个概率可以分为两部分
一是 j1 这个时刻, i1 这个单词还记着,那么j时刻i这个单词不可能忘,因为需要一个时刻来忘掉 i1 这个单词,概率为 f[i1][j1]1
二是 j1 或之前的时刻, i1 这个单词就已经被忘了,那么 j 时刻i这个单词就有p的概率忘掉,所以概率为 (f[i1][j]f[i1][j1])p
总的概率为 f[i][j]=f[i1][j1]1+(f[i1][j]f[i1][j1])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]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值