BZOJ2553 [BJWC2011]禁忌
Description
给你前alphabet个小写字母组成的字符集, 以及n个单词, 定义一个串s的禁忌值为 \(\sum_{i } [s[i] == Taboo[i]]\) , Taboo[i]为第i个单词,现在给定一个长度len,求随机一个用字符集生成的len长度的串的禁忌值的期望.
Solution
听说出题人卡double的精度,所以只能用long double
考虑一个当串给定时如何求禁忌值, 我们将所有单词投影到数轴上, 这就变成一个贪心, 即取尽量多的线段, 使他们互不相交. 因此我们只要建立一个AC自动机, 然后在自动机上走,碰到一个单词节点就返回根节点,并且ANS++,就可以模拟贪心的过程.(因为我们贪心是按照左端点排序,所以先在AC自动机里匹配的一定是左端点靠前的串).
考虑一个经典问题:给定一个图,求从u到v刚好经过m条边的路径条数.(n <= 100, m <= 1e9)
结论:只要把邻接矩阵处理出来,然后求它的n次方后的矩阵中, \(a[u][v]\)的值.
证明:考虑只经过一条边, 那么直接输出\(a[u][v]\)即可,在两条边的情况中,有 \(ans = \sum_{i = 1}^{n} a[u][i] * a[i][v]\)
只要枚举u到v的中转点,然后计算即可. 可以发现这正好是矩阵乘法的定义. 那么求邻接矩阵的k次幂就是两点k步的路径条数.
所以用\(a[u][v]\)设为u一步到v的期望, 那么邻接矩阵自乘k次后也就是u到v走k步的期望值.
我们把AC自动机建出来,并设定一个终点,然后每走到一个节点就设定当前节点到它所有儿子的一步期望为\(1.0/alphabet\), 走到一个标有单词的节点.我们就设定它到根节点与终点的一步期望为\(1.0/alphabet\),然后矩阵乘法即可.
要注意AC自动机上如果一个节点的fail节点是单词节点,那么他本身也是单词节点.
这样我们就不用跳出一个点的子树, 并且也不会给fail的子树加期望加重复.
Codes
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
typedef long long LL;
typedef long double LD;
int read() {
int x = 0, flag = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') flag *= -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 3) + (x << 1) + ch - 48;
ch = getchar();
}
return x * flag;
}
void write(LL a) {
if(a >= 10) write(a / 10);
putchar(a % 10 + '0');
}
#define Maxn 6
#define Maxc 109
struct matrix {
LD data[Maxc][Maxc];
matrix operator * (const matrix b) const {
matrix c;
rep(i, 0, Maxc - 1)
rep(j, 0, Maxc - 1) {
c.data[i][j] = 0;
rep(k, 0, Maxc - 1)
c.data[i][j] += (*this).data[i][k] * b.data[k][j];
}
return c;
}
matrix operator ^ (int times) const {
matrix res, base = (*this);
rep(i, 0, Maxc - 1)
rep(j, 0, Maxc - 1) res.data[i][j] = (i == j);
while(times) {
if(times & 1) res = res * base;
base = base * base;
times >>= 1;
}
return res;
}
}a, b;
#define Maxl ((Maxn) * 16 * 1009)
int vis[Maxl];
int n, len, alphabet;
namespace AC_DFA {
int v[Maxl], t[Maxl][26], cnt = 1, fail[Maxl];
void insert(char str[]) {
int len = strlen(str), cpos = 1;
rep(i, 0, len - 1) {
int id = str[i] - 'a';
if(!t[cpos][id]) t[cpos][id] = ++cnt;
cpos = t[cpos][id];
}
v[cpos] = 1;
}
queue <int> q;
void get_fail() {
q.push(1);
while(!q.empty()) {
int u = q.front(); q.pop();
v[u] |= v[fail[u]];
int pos;
rep(i, 0, alphabet - 1) {
pos = fail[u];
while(pos && !t[pos][i]) pos = fail[pos];
if(t[u][i]) {
fail[t[u][i]] = pos ? t[pos][i] : 1;
q.push(t[u][i]);
}else t[u][i] = pos ? t[pos][i] : 1;
}
}
}
void make_InitalMatrix() {
while(!q.empty()) q.pop();
q.push(1), vis[1] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
rep(i, 0, alphabet - 1) {
if(!vis[t[u][i]]) vis[t[u][i]] = 1, q.push(t[u][i]);
if(v[t[u][i]]) {
a.data[u][cnt + 1] += (LD)1.0 / alphabet;
a.data[u][1] += (LD)1.0 / alphabet;
} else a.data[u][t[u][i]] += (LD)1.0 / alphabet;
}
}
a.data[cnt + 1][cnt + 1] = 1;
}
};
char s[Maxn][16];
int main() {
n = read(), len = read(), alphabet = read();
rep(i, 1, n) scanf("%s", s[i]), AC_DFA :: insert(s[i]);
AC_DFA :: get_fail();
AC_DFA :: make_InitalMatrix();
b = a ^ len;
printf("%.6Lf\n", b.data[1][AC_DFA :: cnt + 1]);
return 0;
}
BZOJ2553 [BJWC2011]禁忌的更多相关文章
- BZOJ2553 [BeiJing2011]禁忌 AC自动机 矩阵
原文链接http://www.cnblogs.com/zhouzhendong/p/8196279.html 题目传送门 - BZOJ2553 题意概括 引用一下lych大佬的: 在字母只有前alph ...
- BZOJ2553: [BeiJing2011]禁忌
2553: [BeiJing2011]禁忌 Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 203 Solved: ...
- BZOJ2553[BeiJing2011]禁忌——AC自动机+概率DP+矩阵乘法
题目描述 Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平.而后,Koishi恢复了读心的能力…… 如今,在John已经成为传 ...
- BZOJ2553 Beijing2011禁忌(AC自动机+动态规划+矩阵快速幂+概率期望)
考虑对一个串如何分割能取得最大值.那么这是一个经典的线段覆盖问题,显然每次取右端点尽量靠前的串.于是可以把串放在AC自动机上跑,找到一个合法串后就记录并跳到根. 然后考虑dp.设f[i][j]表示前i ...
- BZOJ2553 [BeiJing2011]禁忌 【AC自动机 + dp + 矩乘优化】
题目链接 BZOJ2553 题解 话说在前,此题卡精度,最好开long double 先建\(AC\)自动机 求期望,逆着求,设\(f[i][j]\)为长度为\(i\)的串,当前匹配AC自动机\(j\ ...
- [BZOJ2553][BeiJing2011]禁忌 dp+AC自动机+矩阵快速幂
2553: [BeiJing2011]禁忌 Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 1206 Solved ...
- 题解 洛谷 P4569 【[BJWC2011]禁忌】
考虑用\(AC\)自动机来解决本题这样的多字符串匹配问题. 要最大化魔法分割后得到的禁忌串数目,最优情况肯定为在一个串中每个禁忌串的右端点进行分割.对应到\(AC\)自动机上,就是匹配到一个禁忌串后, ...
- BJWC2011 禁忌
题目链接 题解 多模式匹配首先建 AC 自动机,看到 \(len \le 10^9\) 想到矩阵乘法优化. 朴素 DP 关于分割的最大值,可以贪心,只要走到一个能匹配串的点立刻返回根继续匹配就行,一定 ...
- [BJWC2011]禁忌 AC 自动机 概率与期望
#include<cstdio> #include<algorithm> #include<cstring> #include<string> #inc ...
随机推荐
- 一起talk C栗子吧(第一百回:C语言实例--使用信号量进行进程间同步与相互排斥一)
各位看官们.大家好,上一回中咱们说的是进程间同步与相互排斥的样例,这一回咱们说的样例是:使用信号量进行进程间同步与相互排斥. 闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,信号量是由著名 ...
- 新手玩个人server(阿里云)续二
小二班一番厮杀:那英四强诞生:大家闺秀,小家碧玉.窈窕淑女,妍姿俊俏 .不解释! ?不行! 陈冰,李嘉格,刘明湘.张碧晨.大多数的时候,仅仅要脸好看,一切都那么自热而然的顺理成章. 尽管网上骂声四起, ...
- Word 2013安裝字典
不必從內建的字典中開始,Word 2013 可將您連結到 Office 市集,方便您挑選免費的字典,或從包括多語字典的字典集合中購買. 若要選擇並安裝您想要的字典,請以滑鼠右鍵按一下任何單字,並按一下 ...
- 盘点UML中的四种关系
生活中,我们既是独立的个体,又通过联系形成各种关系,比方说:朋友.恋人.父子,同学--于是乎,出现了神乎其神的六人定律. 那么在UML中又存在什么样的关系呢?以下我们来梳理一下. 关联(Associa ...
- Deepin-安装git
sudo apt-get install git 命令介绍(安装软件):apt-get install 命令介绍(Debian系列以管理员运行的前缀):sudo
- IEnumerator<TItem>和IEnumerator Java 抽象类和普通类、接口的区别——看完你就顿悟了
IEnumerable 其原型至少可以说有15年历史,或者更长,它是通过 IEnumerator 来定义的,而后者中使用装箱的 object 方式来定义,也就是弱类型的.弱类型不但会有性能问题,最主要 ...
- EA生成实体类代码
引言 在做机房个人版重构的时候,就听说了EA是一个强大的软件.仅仅只是知道的时候,已经画完了图,没有怎么用EA其它的功能,所以一直没有见识过罢了.如今到了机房合作了,想到EA一定要好好用,这样能省不少 ...
- 10 逻辑完善以及bug修复
进行到这里,我们应用开发已经接近尾声,我这里基本就是应用开发的记录过程,讲解的东西很少,有问题可以在评论区讨论呦.下面进入最后调整的阶段. 预览我们的应用,会发现首页的职位列表,也会显示收藏的星星图标 ...
- 不同linux版本下内核/系统/软件的安装及查询
(一)先介绍下使用apt-get 和使用yum 包管理工具的不同用法: 1.先看yum(redhat) yum的配置文件是/etc/yum.conf 更新:yum update 安装:yum inst ...
- Struts2逻辑视图与视图资源