传送门
先考虑选最多禁忌串的问题
感受一下,如果禁忌串之间没有包含关系,一定是可以从前往后贪心搞的,直接建AC自动机跑匹配,找到一个禁忌串的末尾就回到根上,并把禁忌串数量+1
(所以起初我想的是把包含其他禁忌串的禁忌串去掉再建AC自动机,不过后来发现其实直接跑就可以了,因为顺着跑下去,先到达的末尾节点一定是被包含的禁忌串,包含的禁忌串是跑不到的)
这就是一种经典的AC自动机DP了,每个节点继承fail的状态,然后f[i][j][k]f[i][j][k]表示串长为ii,跑到AC自动机的第jj个节点,当前禁忌串共有kk个的方案数,枚举字符转移即可,复杂度O(len∗|T|∗lenminTi)O(len*\left|T\right|*\frac {len} {\min_{T_i}}),可以得70分
看到len≤109len\leq 10^9,想想能不能加速转移(矩阵乘法?卷积?推公式?)
可是即使能够快速转移,我们计算的是期望,如果依照这种思路做,最后除以总方案数根本没法算,这怎么办呢?
长度为len的字符串中包含的禁忌串数量”的期望等价于“长度为len的字符串经过AC自动机末尾节点的次数”的期望
因为末尾节点独立,根据期望的线性性质,它等于“经过各末尾节点次数”的期望之和
这样我们就把问题转移到考虑每个末尾节点的贡献上
……
然后就不会做了:(,并不是很懂期望的那一套理论,只会矩乘求概率爽爽
询问了红太阳mrazer,理解了一下期望的线性性质,得知只要倒着DP就可以了,这样思路就比较明显了,f[i][j]f[i][j]表示,当前在jj节点,走i~ni~n步的期望经过次数,枚举下一个字符,然后考虑后继点就可以了;而且容易发现,这个东西可以矩乘了,转移矩阵中第i行第j列表示从j节点跳到i节点的概率
对于跳回根节点并数量+1的情况,转移矩阵再加一列常数列,如果能跳回根节点并数量+1,就为1,反之为0;初始矩阵的常数列设为1就可以了
时间复杂度O(|T|3loglen)O(|T|^3\log len)
总结一下,之前也做过一些期望的题目,但感觉根本连门都没入,像这道题目并没有很高的思维难度,也是一堆知识点的堆砌,最后没有想到倒着DP可以做期望,功亏一篑,很不应该,不过也恰恰反应了自身的薄弱,以后还是要加深思考,多做点综合应用和锻炼思维的题目,少写板子题

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int len,alp,n,root=1,cnt=1;
int trie[80][26],fail[80];
char s[17];
bool is_end[80];
queue<int>q;
struct matrix
{int r,c;long double a[80][80];void clr(){r=c=0;memset(a,0,sizeof(a));}
}ini,tra;
matrix operator *(matrix A,matrix B)
{matrix C;C.clr();for (int k=1;k<=A.c;++k)for (int i=1;i<=A.r;++i)if (A.a[i][k]!=0)for (int j=1;j<=B.c;++j)C.a[i][j]+=A.a[i][k]*B.a[k][j];C.r=A.r;C.c=B.c;return C;
}
void insert(char *s)
{int len=strlen(s),now=root;for (int i=0;i<len;++i){if (!trie[now][s[i]-'a']) trie[now][s[i]-'a']=++cnt;now=trie[now][s[i]-'a'];}is_end[now]=1;
}
void build()
{int x,tmp;for (q.push(root);!q.empty();q.pop()){x=q.front();is_end[x]|=is_end[fail[x]];for (int i=0;i<alp;++i)if (trie[x][i]){tmp=fail[x];while (tmp&&!trie[tmp][i]) tmp=fail[tmp];if (tmp&&x!=root) fail[trie[x][i]]=trie[tmp][i];else fail[trie[x][i]]=root;q.push(trie[x][i]);}}
}
main()
{scanf("%d%d%d",&n,&len,&alp);for (int i=1;i<=n;++i)scanf("%s",s),insert(s);build();ini.r=1;ini.c=cnt+1; ini.a[1][cnt+1]=1;tra.r=cnt+1;tra.c=cnt+1;tra.a[cnt+1][cnt+1]=1;for (int i=1;i<=cnt;++i)if (!is_end[i])for (int tmp,j=0;j<alp;++j){tmp=i;while (tmp&&!trie[tmp][j]) tmp=fail[tmp];if (tmp){if (!is_end[trie[tmp][j]]) tra.a[trie[tmp][j]][i]+=1.0/alp;else tra.a[root][i]+=1.0/alp,tra.a[cnt+1][i]+=1.0/alp;}elsetra.a[root][i]+=1.0/alp;}for (;len;len>>=1,tra=tra*tra)if (len&1) ini=ini*tra;printf("%.10lf",(double)ini.a[1][1]);
}

【BZOJ2553】禁忌,AC自动机+期望DP+矩乘相关推荐

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

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

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

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

  3. HDU 3058 Generator [AC自动机+期望DP]

    给出M个短串,这些短串由前N个大写字母组成.然后随机的按字符生成字符串,每次生成1~N个字符的概率是相等的,当生成串包含任意一个指定短串时,就停止生成.问生成串的长度的期望是多少. 首先建立Trie图 ...

  4. BZOJ 2553: [BeiJing2011]禁忌【ACAM + 期望dp + 矩快优化

    --反正瞎瘠薄搞搞,都是显然的 #pragma GCC optimize(3) #include<bits/stdc++.h> #define MAXN 80 using namespac ...

  5. 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 682  Solved: 364 Description 我们称 ...

  6. 【bzoj3530】[Sdoi2014]数数 AC自动机+数位dp

    题目描述 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3223不是幸运 ...

  7. 【BZOJ3530】数数(SDOI2014)-AC自动机+数位DP

    测试地址:数数 做法:本题需要用到AC自动机+数位DP. 首先看到多模式串匹配,自然想到用AC自动机来做.用AC自动机构造出状态转移图后,令f(i,j,k)f(i,j,k)f(i,j,k)为匹配了最高 ...

  8. AC自动机 + 概率dp + 高斯消元 --- HDU 5955 or 2016年沈阳icpc H [AC自动机 + 概率dp + 高斯消元]详解

    题目链接 题目大意: 就是有NNN个人,每个人都会猜一个长度为LLL的只包含{1,2,3,4,5,6}\{1,2,3,4,5,6\}{1,2,3,4,5,6}的序列,现在裁判开始投掷骰子,并且把每次的 ...

  9. ZOJ-3494 BCD Code (ac自动机+数位dp)

    题目链接 Problem Description Binary-coded decimal (BCD) is an encoding for decimal numbers in which each ...

最新文章

  1. Android第十五课 Jni自带的iconv库不支持GBK转码
  2. python连接数据库的技术_Python操作MySQL数据库的三种方法
  3. python中如何求列表中的和_python实现求解列表中元素的排列和组合
  4. file协议访问linux,Mozilla Firefox for Android 'file'协议未授权访问漏洞(CVE-2014-1501)
  5. oracle存储过程行转列,oracle 存储过程-动态行转列,解决。
  6. [开发笔记]-获取歌曲ID3信息
  7. C#中List〈string〉和string[]数组之间的相互转换
  8. linux基本管理命令,linux常用命令与基本管理
  9. V-rep机器人仿真软件使用的学习笔记-续
  10. A - Browsing History
  11. 办理房产证,重要的三张纸
  12. 合成资产赛道之Mirror Protocol
  13. 全志D1-H 双屏异显第一弹来啦 D1同时支持两个屏幕,一边做UI交互,一边播放视频
  14. ROS2极简总结-坐标变换-TF
  15. Shiro框架中实现CA登录及免密功能
  16. 科技对我们生活有哪些影响?未来科技的发展趋势是什么?
  17. SpingBoot+Quartrz生产环境的应用支持分布式、自定义corn、反射执行多任务
  18. 估值“洼地” 煤炭板块再度崛起(附股)
  19. Google Earth Engine(GEE)——全球洪水数据库 v1 (2000-2018年)
  20. GPRS模块SIM900A为什么连接USB-TTL没反应

热门文章

  1. 【DevCloud · 敏捷智库】如何进行需求优先级管理?
  2. 深度学习 GPU环境 Ubuntu 16.04 + Nvidia GTX 1080 + Python 3.6 + CUDA 9.
  3. 浅谈消息队列的原理及优势
  4. android中prop配置参数名,【01-19 技术】安卓系统优化Build.prop 系统参数属性详解...
  5. Java简单记事本设计实验报告_java记事本实验报告
  6. 多维标度法MDS古典解的证明与R语言实现
  7. (组合数学笔记)Pólya计数理论_Part.3_置换群及其性质
  8. python中列表和集合的区别_python中列表和集合有什么区别
  9. IaaS、PaaS和SaaS的区别
  10. android studio 横幅,有关 android studio notification 横幅弹出的功能没有反应