bjoi 2011 禁忌 AC自动机+矩阵乘法

题意: Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平。而后,Koishi恢复了读心的能力……

      

如今,在John已经成为传说的时代,再次造访那座岛屿的人们却发现Koishi遇到了新麻烦。

       这次她遇到了Flandre Scarlet——她拥有可以使用禁忌魔法而不会受到伤害的能力。

       为了说明什么是禁忌魔法及其伤害,引入以下概念:

1.字母集A上的每个非空字符串对应了一个魔法。

其中A是包含了前alphabet个小写字母的集合。

2.有一个集合T,包含了N个字母集A上的字符串

T中的每一串称为一个禁忌串(Taboo string

3.一个魔法,或等价地,其对应的串s因为包含禁忌而对使用者造成的伤害按以下方式确定:

           s分割成若干段,考虑其中是禁忌串的段的数目,不同的分割可能会有不同的数目,其最大值就是这个伤害。

      

由于拥有了读心的能力,Koishi总是随机地使用Flandre Scarlet的魔法,可以确定的是,她的魔法正好对应字母集A上所有长度为len的串

但是,Flandre Scarlet所使用的一些魔法是带有禁忌的,由于其自身特性,她可以使用禁忌魔法而不受到伤害,而Koishi就不同了。可怜的Koishi每一次使用对方的魔法都面临着受到禁忌伤害的威胁。

 

       你现在需要计算的是如果Koishi使用对方的每一个魔法的概率是均等的,那么每一次随机使用魔法所受到的禁忌伤害的期望值是多少。

 

思路:AC自动机 经典题

新建一个节点表示总概率

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 using namespace std;
  6 #define MAXN 100
  7 int n,len,m,top,node_num;
  8 char c[20];
  9 struct matrix
 10 {
 11     double a[MAXN][MAXN];
 12     matrix()
 13     {
 14         memset(a,0,sizeof(a));
 15     }
 16 };
 17 struct node
 18 {
 19     int name,id;
 20     bool end;
 21     node *next[30],*father,*failink;
 22     node()
 23     {
 24         end=0;
 25         memset(next,0,sizeof(next));
 26     }
 27 };
 28 matrix ans,G;
 29 node *head,memo[MAXN],*Q[MAXN];
 30 matrix operator *(const matrix &x,const matrix &y)
 31 {
 32     int i,j,k;
 33     matrix ans;
 34     for(i=0;i<=node_num;i++)
 35     for(j=0;j<=node_num;j++)
 36     for(k=0;k<=node_num;k++)
 37         ans.a[i][j]+=x.a[i][k]*y.a[k][j];
 38     return ans;
 39 }
 40 void insert(char c[])
 41 {
 42     int i,l=strlen(c),x;
 43     node *t=head,*p;
 44     for(i=0;i<l;i++)
 45     {
 46         x=c[i]-'a';
 47         if(t->next[x]==NULL)
 48         {
 49             p=&memo[top]; p->id=top++; p->name=x; t->next[x]=p; p->father=t;
 50         }
 51         t=t->next[x];
 52     }
 53     t->end=1;
 54 }
 55 void set_failure_link()
 56 {
 57     int left,right,i;
 58     node *t,*p;
 59     Q[left=right=1]=head;
 60     while(left<=right)
 61     {
 62         t=Q[left++];
 63         if(t->father==head) t->failink=head;
 64         else if(t!=head)
 65         {
 66             int x=t->name;
 67             p=t->father->failink;
 68             t->failink=p->next[x];
 69             if(p->next[x]->end==1) t->end=1;
 70         }
 71         for(i=0;i<m;i++)
 72         {
 73             if(t->next[i]!=NULL) Q[++right]=t->next[i];
 74             else 
 75             {
 76                 if(t==head) t->next[i]=head;
 77                 else t->next[i]=t->failink->next[i];
 78             }
 79         }
 80     }
 81 }
 82 void build_matrix()
 83 {
 84     node_num=top;
 85     int i,j;
 86     for(i=0;i<top;i++)
 87     if(memo[i].end!=1)
 88     {
 89         for(j=0;j<m;j++)
 90         {
 91             if(memo[i].next[j]->end==1)
 92             {
 93                 G.a[i][0]+=1/(double)m;G.a[i][top]+=1/(double)m;
 94             }
 95             else
 96             G.a[i][memo[i].next[j]->id]+=1/(double)m;
 97         }
 98     }
 99     G.a[top][top]=1;
100 }
101         
102 double matrix_pow(int n)
103 {
104     int i,j;
105     for(i=0;i<=node_num;i++) ans.a[i][i]=1;
106     while(n>0)
107     {
108         if(n&1) ans=ans*G;
109         G=G*G;
110         n>>=1;
111     }
112     return ans.a[0][node_num];
113 }
114 int main()
115 {
116     freopen("taboo.in","r",stdin);
117     freopen("taboo.out","w",stdout);
118     memset(memo,0,sizeof(memo));
119     scanf("%d%d%d",&n,&len,&m);
120     int i,j;
121     top=0;
122     head=&memo[top]; head->id=top++;
123     for(i=1;i<=n;i++)
124     {
125         scanf("%s",c);
126         insert(c);
127     }
128     set_failure_link();
129     build_matrix();
130     printf("%lf\n",matrix_pow(len));
131     return 0;
132 }

posted on 2012-05-03 20:12  myoi  阅读(409)  评论(0编辑  收藏  举报

导航