【JZOJ5167】下蛋爷

来源:互联网 发布:ipad的蜂窝移动数据 编辑:程序博客网 时间:2024/04/27 09:24

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 200010using 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]]);}
原创粉丝点击