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

【评分方法】

对于每一组数据,如果没有得到正确的输出(TLE、MLE、RTE、输出格式错误等)得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,我们能干什么

建图如下:

  1. void build()
  2. {
  3. vis[]=;
  4. q.push();long double tmp=1.0/k;
  5. while(!q.empty())
  6. {
  7. int x=q.front();q.pop();
  8. for0(i,k-)
  9. {
  10. if(!vis[t[x][i]])vis[t[x][i]]=,q.push(t[x][i]);
  11. if(v[t[x][i]])
  12. {
  13. a.d[x][n]+=tmp;
  14. a.d[x][]+=tmp;
  15. }else a.d[x][t[x][i]]+=tmp;
  16. }
  17. }
  18. }

意思就是我们把所有这样的关系找出来,如果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=,f=;char ch=getchar();
  50.  
  51. while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
  52.  
  53. while(ch>=''&&ch<=''){x=*x+ch-'';ch=getchar();}
  54.  
  55. return x*f;
  56.  
  57. }
  58. int n,m,k,cnt,t[maxn][],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,,sizeof(d));}
  66. }a,b,c;
  67. inline void add()
  68. {
  69. scanf("%s",s+);int len=strlen(s+),now=;
  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]=;
  77. }
  78. void bfs()
  79. {
  80. q.push();
  81. while(!q.empty())
  82. {
  83. int x=q.front(),y,j;q.pop();
  84. v[x]|=v[go[x]];
  85. for0(i,k-)
  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]:;
  92. q.push(y);
  93. }else t[x][i]=j?t[j][i]:;
  94. }
  95. }
  96. }
  97. void build()
  98. {
  99. vis[]=;
  100. q.push();long double tmp=1.0/k;
  101. while(!q.empty())
  102. {
  103. int x=q.front();q.pop();
  104. for0(i,k-)
  105. {
  106. if(!vis[t[x][i]])vis[t[x][i]]=,q.push(t[x][i]);
  107. if(v[t[x][i]])
  108. {
  109. a.d[x][n]+=tmp;
  110. a.d[x][]+=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>>=,a=a*a)
  127. if(cs&)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=;
  147. for1(i,n)add();
  148. bfs();
  149. n=cnt+;
  150. build();
  151. for1(i,n)b.d[i][i]=;
  152. a.d[n][n]=;
  153. ksm(m);
  154. printf("%.7f\n",(double)b.d[][n]);
  155.  
  156. return ;
  157.  
  158. }

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

UPD:以上纯属口胡。。。

一个边权为1的邻接矩阵自乘n次,则a[s][t]代表从s恰好经过n条边到t的路径条数。

根据这一点我们可以推广

令a[i][j]表示一步从i到j的期望,那么a自乘n次就a[s][t]就代表从s恰好经过n条边到达t的期望。

然后我们新建了一给点n=cnt+1

然后我们要求sigma(从1到n恰好经过j条边的期望)j<=len

所以我们要设值a[n][n]=1,因为下一次计算的时候b[1][n]=。。。+b[1][n]*a[n][n]+。。。就可以把上一次的答案累计。

就算是我懂了QAQ

BZOJ2553: [BeiJing2011]禁忌的更多相关文章

  1. [BZOJ2553][BeiJing2011]禁忌 dp+AC自动机+矩阵快速幂

    2553: [BeiJing2011]禁忌 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1206  Solved ...

  2. BZOJ2553 [BeiJing2011]禁忌 AC自动机 矩阵

    原文链接http://www.cnblogs.com/zhouzhendong/p/8196279.html 题目传送门 - BZOJ2553 题意概括 引用一下lych大佬的: 在字母只有前alph ...

  3. BZOJ2553[BeiJing2011]禁忌——AC自动机+概率DP+矩阵乘法

    题目描述 Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平.而后,Koishi恢复了读心的能力…… 如今,在John已经成为传 ...

  4. BZOJ2553 Beijing2011禁忌(AC自动机+动态规划+矩阵快速幂+概率期望)

    考虑对一个串如何分割能取得最大值.那么这是一个经典的线段覆盖问题,显然每次取右端点尽量靠前的串.于是可以把串放在AC自动机上跑,找到一个合法串后就记录并跳到根. 然后考虑dp.设f[i][j]表示前i ...

  5. BZOJ2553 [BeiJing2011]禁忌 【AC自动机 + dp + 矩乘优化】

    题目链接 BZOJ2553 题解 话说在前,此题卡精度,最好开long double 先建\(AC\)自动机 求期望,逆着求,设\(f[i][j]\)为长度为\(i\)的串,当前匹配AC自动机\(j\ ...

  6. 【BZOJ】2553: [BeiJing2011]禁忌 AC自动机+期望+矩阵快速幂

    [题意]给定n个禁忌字符串和字符集大小alphabet,保证所有字符在集合内.一个字符串的禁忌伤害定义为分割能匹配到最多的禁忌字符串数量(一个可以匹配多次),求由字符集构成的长度为Len的字符串的期望 ...

  7. 【BZOJ2553】[BeiJing2011]禁忌 AC自动机+期望DP+矩阵乘法

    [BZOJ2553][BeiJing2011]禁忌 Description Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平. ...

  8. 【bzoj2553】[BeiJing2011]禁忌

    2553: [BeiJing2011]禁忌 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 595  Solved: ...

  9. bzoj 2553 [BeiJing2011]禁忌——AC自动机+概率DP+矩阵

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2553 看了题解才会…… 首先,给定一个串,最好的划分方式是按禁忌串出现的右端点排序,遇到能填 ...

随机推荐

  1. 九度OJ 1510 替换空格

    题目地址:http://ac.jobdu.com/problem.php?pid=1510 题目描述: 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We ...

  2. PHP 各种函数

    usleep() 函数延迟代码执行若干微秒. unpack() 函数从二进制字符串对数据进行解包. uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID. time_sleep_unti ...

  3. 《jQuery、jQuery UI及jQuery Mobile技巧与示例》勘误收集

    此书由程学彬 (http://weibo.com/ironbin)和我合译完成,此篇博客作为勘误收集而用,若译文有误或者有任何疑问,欢迎留下评论,或者给我发邮件(地址:gzooler@gmail.co ...

  4. ASP.NET 实现简单的图片防盗链介绍

    在此,网站图片防盗链的方法是,通过获取Http请求头中的 Referer 标头与本网站域名比较,来判断用户是否来自本站跳转过来的 . 创建一个全局处理程序,用来处理images目录下的图片的直接请求: ...

  5. C# 实体model验证输出

    新建Model实体: [Required(ErrorMessage = @"地址 1 为必填项!")] [StringLength(, ErrorMessage = @" ...

  6. 一个空格也可以让html格式显示大不相同

    今天在编写html时出现了bug,有两个标签一直贴近显示,但是两段代码完全一样前一段就没有问题. 错误代码如下 <div id="tool1" style="wid ...

  7. 布局时margin会影响父元素

    布局时margin会影响父元素.md 在布局使用margin时 <div class="login-bg"> <div class="login&quo ...

  8. CSS3的position:sticky介绍

    用户的屏幕越来越大,而页面太宽的话会不宜阅读,所以绝大部分网站的主体宽度和之前相比没有太大的变化,于是浏览器中就有越来越多的空白区域,所以你可能注意到很多网站开始在滚动的时候让一部分内容保持可见,比如 ...

  9. c++二分答案 之 跳石头

    题目: 题目描述 Description 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之 ...

  10. 查看uCOS-II的CPU使用率

    代码模板: void main(void) { OSInit(); /* 安装uCOS-II的任务切换向量 */ /* 创建用户起始任务TaskStart */ OSStart(); } void T ...