首页 > 代码库 > BZOJ2553: [BeiJing2011]禁忌

BZOJ2553: [BeiJing2011]禁忌

2553: [BeiJing2011]禁忌

Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge
Submit: 203  Solved: 75
[Submit][Status]

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

第一行包含三个正整数Nlenalphabet

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

 

Output

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

 

 

Sample Input

2 4 2

aa

abb

Sample Output

0.75

【样例1解释】
一共有2^4 = 16种不同的魔法。

需要注意的是“aabb”的禁忌伤害是1而不是2。

HINT

100%的数据中N ≤ 5len ≤1091 ≤ alphabet ≤ 26

 

在所有数据中,有不少于40%的数据中:N = 1

 

数据保证每个串Ti的长度不超过15,并且不是空串。

 

数据保证每个Ti均仅含有前alphabet个小写字母。

 

数据保证集合T中没有相同的元素,即对任意不同的ij,有TiTj

 

【评分方法】

 

对于每一组数据,如果没有得到正确的输出(TLEMLERTE、输出格式错误等)得0分。

 

否则:设你的输出是YourAns,标准输出是StdAns

 

MaxEPS = max(1.0 , StdAns)×10-6

 

如果|YourAns – StdAns| ≤ MaxEPS则得10分,否则得0分。


即:你的答案需要保证相对误差或绝对误差不超过10-6

题解:

出题人果然丧心病狂卡精度。。。

这题写题解的人好像不多,也许是我太傻叉了,时光机的代码画面太美我都不敢看了。。。

 首先我们先搞清一个问题,如果给定了一个字符串,那么它的伤害指数是多少。

转化一下就变成 在一个数轴上给定若干条线段,请选出最多的线段并且使得这些线段两两交集为空。

然后这就是一个贪心水题,见http://www.cnblogs.com/zyfzyf/p/4006703.html

我们只要按右端点排序,能取就取。

那假如我们已经构建了一个AC自动机,我们只要走到一个危险节点,就ans++,并且退回到根节点重新开始走。

可以看出,这样正好相当于在模拟上面的贪心过程。

然后我们看看len增加1,我们能干什么

建图如下:

void build(){    vis[1]=1;    q.push(1);long double tmp=1.0/k;    while(!q.empty())    {        int x=q.front();q.pop();        for0(i,k-1)        {            if(!vis[t[x][i]])vis[t[x][i]]=1,q.push(t[x][i]);            if(v[t[x][i]])            {                a.d[x][n]+=tmp;                a.d[x][1]+=tmp;            }else a.d[x][t[x][i]]+=tmp;        }    }}

意思就是我们把所有这样的关系找出来,如果len结束时,我们在x。

那如果t[x][i]是根节点,那我们就有1.0/alp的期望使ans+1,并返回根节点,否则我们有1.0/alp的期望走到t[x][i]。

最后我们求长度为给定是从1走到ans(设置为节点n)的期望次数即可。

然后这个矩阵构建出来我们发现 i到j的期望就等于sigma(i到k的期望*k到j的期望)。

这正好是矩阵乘法!

然后我们就可用快速幂加速了。

注意设置a[n][n]=1

代码:

  1 #include<cstdio>  2   3 #include<cstdlib>  4   5 #include<cmath>  6   7 #include<cstring>  8   9 #include<algorithm> 10  11 #include<iostream> 12  13 #include<vector> 14  15 #include<map> 16  17 #include<set> 18  19 #include<queue> 20  21 #include<string> 22  23 #define inf 1000000000 24  25 #define maxn 200+5 26  27 #define eps 1e-10 28  29 #define ll long long 30  31 #define pa pair<int,int> 32  33 #define for0(i,n) for(int i=0;i<=(n);i++) 34  35 #define for1(i,n) for(int i=1;i<=(n);i++) 36  37 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 38  39 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 40  41 #define mod 1000000007 42  43 using namespace std; 44  45 inline int read() 46  47 { 48  49     int x=0,f=1;char ch=getchar(); 50  51     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} 52  53     while(ch>=0&&ch<=9){x=10*x+ch-0;ch=getchar();} 54  55     return x*f; 56  57 } 58 int n,m,k,cnt,t[maxn][26],go[maxn]; 59 bool v[maxn],vis[maxn]; 60 queue<int>q; 61 char s[maxn]; 62 struct matrix 63 { 64     long double d[maxn][maxn]; 65     matrix(){memset(d,0,sizeof(d));} 66 }a,b,c; 67 inline void add() 68 { 69     scanf("%s",s+1);int len=strlen(s+1),now=1; 70     for1(i,len) 71     { 72         int x=s[i]-a; 73         if(!t[now][x])t[now][x]=++cnt; 74         now=t[now][x]; 75     } 76     v[now]=1; 77 } 78 void bfs() 79 { 80     q.push(1); 81     while(!q.empty()) 82     { 83         int x=q.front(),y,j;q.pop(); 84         v[x]|=v[go[x]]; 85         for0(i,k-1) 86         { 87             j=go[x]; 88             while(j&&!t[j][i])j=go[j]; 89             if(t[x][i]) 90             { 91                 go[y=t[x][i]]=j?t[j][i]:1; 92                 q.push(y); 93             }else t[x][i]=j?t[j][i]:1; 94         } 95     } 96 }     97 void build() 98 { 99     vis[1]=1;100     q.push(1);long double tmp=1.0/k;101     while(!q.empty())102     {103         int x=q.front();q.pop();104         for0(i,k-1)105         {106             if(!vis[t[x][i]])vis[t[x][i]]=1,q.push(t[x][i]);107             if(v[t[x][i]])108             {109                 a.d[x][n]+=tmp;110                 a.d[x][1]+=tmp;111             }else a.d[x][t[x][i]]+=tmp;112         }113     }114 }115 inline matrix operator *(matrix &x,matrix &y)116 {117     matrix z;118     for1(i,n)119      for1(j,n)120       for1(l,n)121        z.d[i][j]+=x.d[i][l]*y.d[l][j];122     return z;123 }124 void ksm(int cs)125 {126     for(;cs;cs>>=1,a=a*a)127         if(cs&1)b=b*a;128 }129 void printb()130 {131     for1(i,n)for1(j,n)cout<<i<< <<j<< <<b.d[i][j]<<endl;132 }133 void printa()134 {135     for1(i,n)for1(j,n)cout<<i<< <<j<< <<a.d[i][j]<<endl;136 }137 138 int main()139 140 {141 142     freopen("input.txt","r",stdin);143 144     freopen("output.txt","w",stdout);145 146     n=read();m=read();k=read();cnt=1;147     for1(i,n)add();148     bfs();149     n=cnt+1;150     build();151     for1(i,n)b.d[i][i]=1;152     a.d[n][n]=1;153     ksm(m);154     printf("%.7f\n",(double)b.d[1][n]);155 156     return 0;157 158 }  
View Code

 真是一道综合性的难题+好题!

BZOJ2553: [BeiJing2011]禁忌