杭州现场J题_Infinite monkey theorem

来源:互联网 发布:myeclipse可视化编程 编辑:程序博客网 时间:2024/05/16 09:01

构造一个DFA,  对于样例:

2 100

a 0.312345

b 0.687655

abab

即:

    (b)

-----------

 |       /

 |      /

 |    /

//  /

           (a)      (b)         (a)         (b)                       

NULL----->a---->ab---->aba---->abab(ACC,成功状态)

/ /           //   /         /             /                                                  

 |            / (a) /         /     (a)   /                     

 |           -----------------/----------

 |                                   /

 |              (b)                  /

 --------------------------------       

(这幅图画的不错么?= =!)                         

然后就是DP了, 枚举敲击数i,敲了i个键处于的状态j,按键k,计算出在j这个状态按k会转移到的状态next_t

DP方程:dp[i+1][next_t]+=p[k]*dp[i][j];(dp[i][j]表示敲了i个键后处于j状态的概率)

写的时候脑残的自动机漏了一句话调了n久= =!

然后又用KMP的子串自匹配加状态映射又构造了个DFA,速度竟然比AC自动机慢,不过这题状态这么小怎么都不可能超时的,本来还想写一个暴力构自动机的,实在是没心情遂作罢,顺便还复习了下KMP,还A了道题= =!

PS:计算下标什么的最讨厌了= =!

AC自动机版:

/*
TRIE结构,在使用前必须调用初始化init()!!!
主要调用Ins,ser,返回值都是TRIE中的下标;del,返回有无字符串(删除成功否)
*/
#include<stdio.h>
#include<iostream>
#include<memory.h>
#include<queue>
using namespace std;
const int CTNUM = 26;  //储存字母的数目
const int STRNUM = 15000; //节点数目,绝对不能少于给定的字符串数目,一般给大点
const int MINCHAR='a';  //大小写分辨,如果混用或者不连续的话需要有对应的hash函数
struct TRIE
{
 int son[CTNUM];
 int count;
 int father;
}trie[STRNUM];
int fail[STRNUM];
int TNUM=1;
queue<int> q;
int n;
#define INT_MAX 10000000
int map[300][300];
void init()
{
 memset(&trie[0],0,sizeof(TRIE));
 memset(&trie[1],0,sizeof(TRIE));
 TNUM=2;
}
int Ins(char *str,int len)
{
 int i;
 int cur=1;
 for(i=0;i<len;i++)
 {
  if( !trie[cur].son[str[i]-MINCHAR] )
  {
   memset( &trie[TNUM],0,sizeof(TRIE) );
   trie[TNUM].father=cur;
   cur=trie[cur].son[str[i]-MINCHAR]=TNUM++;
  }
  else cur=trie[cur].son[str[i]-MINCHAR];
 }
 trie[cur].count++;
 return cur;
}
void calc_fail()
{
 int i,k,p;
 fail[0]=0;
 fail[1]=0;
 memset(fail,0,sizeof(fail));
 while(!q.empty()) q.pop();
 q.push(1);
 while(!q.empty())
 {
  i=q.front();
  q.pop();
  for(k='a'-MINCHAR;k<='z'-MINCHAR;k++)
  if (trie[i].son[k]!=0)
  {
                  int p=fail[i];
      while(p!=0&&trie[p].son[k]==0)
       p=fail[p];
      if (!p) fail[trie[i].son[k]]=1;
      else
      fail[trie[i].son[k]]=trie[p].son[k];
   q.push(trie[i].son[k]);
  }
 }
}
double p[300],dp[1005][50],ans;
char s[300];
int main()
{
 int n,m,i,j,x,k,next_t,t;
 while(scanf("%d %d",&n,&m)!=EOF)
 {
  if (n==0&&m==0) break;
  memset(p,0,sizeof(p));
      for(i=1;i<=n;i++)
   {
    scanf("%s",s);
       scanf("%lf",&p[s[0]-MINCHAR]);
   }
      scanf("%s",s);
   init();
   Ins(s,strlen(s));
   calc_fail();  
   ans=0;
   memset(dp,0,sizeof(dp));
   dp[0][1]=1;
   for(i=0;i<=m-1;i++)
  for(j=0;j<=TNUM-2;j++)
    for(k='a'-MINCHAR;k<='z'-MINCHAR;k++)
     {
       t=j;
     while(t!=0&&trie[t].son[k]==0)
      t=fail[t];
     if (t==0) next_t=1;
     else
     next_t=trie[t].son[k];
      dp[i+1][next_t]+=p[k]*dp[i][j];
     }
  for(i=1;i<=m;i++)
   ans+=dp[i][TNUM-1];
  printf("%.2lf%%/n",ans*100);
 }

}

KMP版:

#include<stdio.h>
#include<iostream>
#include<memory.h>
#include<queue>
using namespace std;
const int MINCHAR='a';        //大小写分辨,如果混用或者不连续的话需要有对应的hash函数
int n;
int map[300][300];
int next[100];
void get_next(char *s)
{
    int i,j,l;
 memset(next,0,sizeof(next));
    l=strlen(s);
    i=-1;next[0]=-1;j=-1;
    for(i=1;i<=l-1;i++)
 {
  while(s[j+1]!=s[i]&&j!=-1) j=next[j];
  if (s[j+1]==s[i]) j++;
  next[i]=j;
 }
}
double p[300],dp[1005][50],ans;
char s[300];
void calc_map()
{
    int i,j,l,t,next_t;
    memset(map,0,sizeof(map));
    l=strlen(s);
    for(i=0;i<=l-1;i++)
     for(j='a';j<='z';j++)
    {
     t=i-1;
              while(s[t+1]!=j&&t!=-1) t=next[t];
     if (s[t+1]==j) t++;
     map[i][j-MINCHAR]=t+1;
    }
}
void calc_dp(int m)
{
    int i,j,k,l;
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    l=strlen(s);
    for(i=0;i<=m-1;i++)
        for(j=0;j<=l-1;j++)
           for(k='a'-MINCHAR;k<='z'-MINCHAR;k++)
               dp[i+1][map[j][k]]+=p[k]*dp[i][j];
}
int main()
{
    int n,m,i,j,x,k;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if (n==0&&m==0) break;
        memset(p,0,sizeof(p));
      for(i=1;i<=n;i++)
      {
          scanf("%s",s);
          scanf("%lf",&p[s[0]-MINCHAR]);
      }
      scanf("%s",s);
      get_next(s);
      calc_map();
      memset(dp,0,sizeof(dp));
      dp[0][1]=1;
      ans=0;
     calc_dp(m);
     for(i=1;i<=m;i++)
         ans+=dp[i][strlen(s)];
     printf("%.2lf%%/n",ans*100);
    }

}