题目大意:给定n个模式串,定义一个字符串的伤害为所有子串的划分中最多包含的模式串数量,求长度为len的字符串的伤害期望值
小五prpr,恋恋prpr,大小姐prpr
首先建立AC自动机 令f[i][j]表示长度为i的字符串在AC自动机上的第j个节点的伤害期望值
如果要走到某个节点是危险节点或者fail指针指向危险节点,就ans++,然后回到根节点
这样构造出来的矩阵做快速幂= = 这么做都会把- - 不会别骂我- -
但是跑完发现找不到答案- - 因此我们需要稍微改造一下- -
新建一个节点 如果某个节点因为危险返回了根 就同时向该节点连一条边
新节点的唯一一条出边边权为1指向自己- - 这样搞出来的邻接矩阵自乘len次,得到的矩阵的[root][new_node]就是答案- -
相当于把AC自动机看成一个图 去图上求根到新节点走恰好len步的期望值
好题- - 注意开long double不然卡精- - 虽说如此总比那些用double去卡long double精度的题强- -
大半夜的我写的是啥自己都看不懂了- - 没看懂的地方去看代码吧但愿写的还能清晰点。。。 吧。。。
#include <cstdio> #include <cstring> #include <iomanip> #include <iostream> #include <algorithm> #define M 110 using namespace std; int n,len,alphabet; char s[M]; namespace Aho_Corasick_Automaton{ struct Trie{ Trie *son[26],*fail; bool ed; }mempool[M],*C=mempool,*root; void Insert(Trie* &p,char *s) { if(!p) p=C++; if(!*s) { p->ed=1; return ; } Insert(p->son[(*s)-'a'],s+1); } void Build_Tree() { static Trie *q[M]; int i,r=0,h=0; for(i=0;i<26;i++) if(root->son[i]) (q[++r]=root->son[i])->fail=root; else root->son[i]=root; while(r!=h) { Trie *p=q[++h]; for(i=0;i<26;i++) if(p->son[i]) { p->son[i]->fail=p->fail->son[i]; p->son[i]->ed|=p->fail->son[i]->ed; q[++r]=p->son[i]; } else p->son[i]=p->fail->son[i]; } } } namespace Matrix_Multiplication{ int size; struct Matrix{ long double memory[M][M]; Matrix() { memset(memory,0,sizeof memory); } long double* operator [] (int x) { return memory[x]; } friend void operator *= (Matrix &x,Matrix &y) { int i,j,k; Matrix z; for(i=0;i<=size;i++) for(j=0;j<=size;j++) for(k=0;k<=size;k++) z[i][j]+=x[i][k]*y[k][j]; x=z; } }f; Matrix Quick_Power(Matrix x,int y) { Matrix re; for(int i=0;i<=size;i++) re[i][i]=1; while(y) { if(y&1) re*=x; x*=x;y>>=1; } return re; } } int main() { using namespace Aho_Corasick_Automaton; using namespace Matrix_Multiplication; int i,j; cin>>n>>len>>alphabet; for(i=1;i<=n;i++) { scanf("%s",s+1); Insert(root,s+1); } Build_Tree(); size=C-mempool; long double temp=1.0/alphabet; for(j=0;j<size;j++) { for(i=0;i<alphabet;i++) { int k; if(mempool[j].son[i]->ed) { f[j][0]+=temp; f[j][size]+=temp; } else f[j][mempool[j].son[i]-mempool]+=temp; } } f[size][size]=1; Matrix ans=Quick_Power(f,len); cout<<fixed<<setprecision(10)<<ans[0][size]; return 0; }
BZOJ 2553 BeiJing2011 禁忌 AC自动机+矩阵乘法
原文地址:http://blog.csdn.net/popoqqq/article/details/42653953