zoukankan      html  css  js  c++  java
  • 【bzoj2553】[BeiJing2011]禁忌

    2553: [BeiJing2011]禁忌

    Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge
    Submit: 595  Solved: 231
    [Submit][Status][Discuss]

    Description

           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使用对方的每一个魔法的概率是均等的,那么每一次随机使用魔法所受到的禁忌伤害的期望值是多少。

    Input

    第一行包含三个正整数N、len、alphabet。

    接下来N行,每行包含一个串Ti,表示禁忌串。

    Output

    一个非负实数,表示所受到禁忌伤害的期望值。

    Sample Input

    2 4 2
    aa
    abb

    Sample Output

    0.75

     
     
     
     
    【题解】
     
    这是一道神题,出题人卡精度什么的就不说了。
     
    首先把模式串建成AC自动机(或trie图),然后考虑在AC自动机上的转移。
     
    对于每一步转移,都有两种情况:
     
    1、子结点没被标记(即不是模式串的结尾单词),有1/alphabet的期望转移到这个子结点。
     
    2、子结点被标记,有1/alphabet的期望值转移到根,并且用一个新结点记录答案。
     
    这样我们可以考虑构造一个矩阵a[i][j],记录下来结点之间的转移关系。
     
    然后矩阵自乘m次得到的矩阵ans,ans[0][cnt+1]就是答案。
     
    解释一下:对于从i结点转移到j结点,存在一个结点k,使得从i转移到k,然后再转移到j,这就是矩阵乘法的意义。
     
    看了zyf的代码,学到了一种写矩阵乘法的好方法:把矩阵存成结构体,然后定义一种矩阵乘运算,很效率。
     
    调试的时候遇到了一个问题,这题必须用long double,然而long double数组开到了417*417就会出现很奇怪的现象(读者可以自行尝试),只能开到416*416.
     
    具体见代码:
     
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<ctime>
     6 #include<cmath>
     7 #include<algorithm>
     8 using namespace std;
     9 #define MAXN 205
    10 struct node{long double p[MAXN][MAXN];node(){memset(p,0,sizeof(p));}}a,ans;
    11 int n,m,K,cnt,end[MAXN],q[MAXN],fail[MAXN],vis[MAXN],tr[MAXN*5][27];
    12 char ch[MAXN];
    13 inline int read()
    14 {
    15     int x=0,f=1;  char ch=getchar();
    16     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
    17     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
    18     return x*f;
    19 }
    20 inline node operator *(node &x,node &y)//定义矩阵乘运算
    21 {
    22     node z;
    23     for(int i=0;i<=cnt+1;i++)
    24         for(int j=0;j<=cnt+1;j++)
    25             for(int k=0;k<=cnt+1;k++)
    26                 z.p[i][j]+=x.p[i][k]*y.p[k][j];
    27     return z;
    28 }
    29 void insert()
    30 {
    31     int now=0,len=strlen(ch+1);  
    32     for(int i=1;i<=len;i++)
    33     {
    34         if(!tr[now][ch[i]-'a'])  tr[now][ch[i]-'a']=++cnt;
    35         now=tr[now][ch[i]-'a'];
    36     }
    37     end[now]=1;
    38 }
    39 void build()
    40 {
    41     int head=0,tail=0;
    42     for(int i=0;i<K;i++) if(tr[0][i]) q[++tail]=tr[0][i];
    43     while(++head<=tail)
    44     {
    45         int x=q[head];
    46         for(int i=0;i<K;i++)
    47         {
    48             if(!tr[x][i])  tr[x][i]=tr[fail[x]][i];
    49             else {fail[tr[x][i]]=tr[fail[x]][i];  q[++tail]=tr[x][i];}
    50         }
    51     }
    52 }
    53 void get()
    54 {
    55     int head=0,tail=1; long double chty=(long double)1.0/K;//期望常数
    56     q[1]=0; vis[0]=1;
    57     while(++head<=tail)
    58     {
    59         int x=q[head];
    60         for(int i=0;i<K;i++)
    61         {
    62             if(!vis[tr[x][i]])  vis[tr[x][i]]=1,q[++tail]=tr[x][i];
    63             if(end[tr[x][i]])  a.p[x][cnt+1]+=chty,a.p[x][0]+=chty;
    64             else a.p[x][tr[x][i]]+=chty;
    65         }
    66     }
    67     a.p[cnt+1][cnt+1]=1;
    68 }
    69 int main()
    70 {
    71     //freopen("cin.in","r",stdin);
    72     //freopen("cout.out","w",stdout);
    73     n=read();  m=read();  K=read();
    74     for(int i=1;i<=n;i++)  {scanf("%s",ch+1);  insert();}
    75     build(); 
    76     get();
    77     for(int i=0;i<=cnt+1;i++)  ans.p[i][i]=1;
    78     for(;m;m>>=1,a=a*a)  if(m&1) ans=ans*a;
    79     printf("%.7f
    ",(double)ans.p[0][cnt+1]);
    80     return 0;
    81 }
     
  • 相关阅读:
    内存泄漏 Memory Leaks 内存优化 MD
    Handler Thread 内部类引起内存泄露分析
    为什么不取消注册BroadcastReceiver会导致内存泄漏
    WebChromeClient 简介 API 案例
    WebViewClient 简介 API 案例
    java.net.URI 简介 文档 API
    android.net.Uri 简介 API
    RV 多样式 MultiType 聊天界面 消息类型 MD
    JS函数声明与定义,作用域,函数声明与表达式的区别
    CSS中table tr:nth-child(even)改变tr背景颜色: IE7,8无效
  • 原文地址:https://www.cnblogs.com/chty/p/6007514.html
Copyright © 2011-2022 走看看