【JZOJ5167】下蛋爷

40 篇文章 0 订阅
24 篇文章 0 订阅

Description

这里写图片描述

Solution

首先我们假设知道每个单词出现的次数,那么对于相同的出现次数只保留一个。

例如出现次数为: a1,a2,a2,a2,a3 ,只保留 a1,a2,a3

将它们排序后,我们的到一个从大到小的序列,那么这个序列第 i 次阅读后面i个就有可能被遗忘。

Fi,j 为第 i 次阅读,j记住的概率,则如果前面那次阅读的后面一个 j+1 记住,那么本轮 j 将不会被遗忘,则有Fi,j=Fi1,j+1

如果 i1 次阅读时 j+1 遗忘了,那么有 (Fi1,jFi1,j+1)p 的概率会记住(表示 i1 次j能记住且 j+1 记不住的概率)。

总的转移式为: Fi,j=Fi1,j+1+(Fi1,jFi1,j+1)p

求每个单词出现的次数,kmp卡卡常可能会过(没试过)。当然AC自动机是首选。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
#define N 210
#define K 1010
#define M 200010
using namespace std;
double f[K][N];
char s[N][30];
char ss[K*K];
int wz[N];
int nn=0;
int tr[M][27],dep[M],tot=1,fail[M],up[M],b[M];
struct node{
    int x,wz;
}a[N];
bool cmp(node x,node y){
    return x.x>y.x;
}
void insert(int x)
{
    int l=strlen(s[x]+1),rt=1;
    fo(i,1,l)
    {
        int ch=s[x][i]-'a'+1;
        if(!tr[rt][ch]) tr[rt][ch]=++tot;
        dep[tr[rt][ch]]=dep[rt]+1,rt=tr[rt][ch];
    }
    tr[rt][0]=1;
    b[rt]=x;
}
void makefail()
{
    queue<int> q;
    q.push(1);
    while(!q.empty())
    {
        int x=q.front(),p=0;
        q.pop();
        fo(i,1,26)
        {
            int v=tr[x][i];
            if(!v) continue;
            int j=fail[x];
            while(j && !tr[j][i]) j=fail[j];
            fail[v]=tr[j][i];
            q.push(v);
            if(!fail[v]) fail[v]=1;
            up[v]=b[fail[v]]?fail[v]:up[fail[v]];
        }
    }
}
void query()
{
    int l=strlen(ss+1);
    int rt=1;
    fo(i,1,l)
    {
        int j=ss[i]-'a'+1;
        while(rt!=1 && !tr[rt][j]) rt=fail[rt];
        rt=tr[rt][j];
        if(!rt) rt=1;
        int p=rt;
        while(p>1) a[b[p]].x++,p=up[p];
    }
}
int main()
{
    int n,q;
    scanf("%d",&n);
    fo(i,1,n)
    {
        scanf("%s",s[i]+1);
        insert(i),a[i].wz=i;
    }
    makefail();
    scanf("%s",ss+1);
    query();
    sort(a+1,a+n+1,cmp);
    a[0].x=-1;
    fo(i,1,n)
    {
        if(a[i].x!=a[i-1].x) nn++;
        wz[a[i].wz]=nn;
    }
    double p;
    scanf("%lf %d",&p,&q);
    fo(i,1,nn-1) f[1][i]=1;
    f[1][nn]=p;
    fo(i,2,q)
    {
        f[i][nn]=f[i-1][nn]*p;
        fo(j,1,nn-1)
        f[i][j]=f[i-1][j+1]+(f[i-1][j]-f[i-1][j+1])*p;
    }
    fo(i,1,n) printf("%.3lf ",f[q][wz[i]]);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值