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

首先我们把这些串扔到AC自动机上。。。

可以发现要匹配尽可能多的子串,我们只要贪心地在AC自动机上匹配即可

所以建完trie树后需要删去是某个模版串后缀的所有模版串

然后我们根据AC自动机上的状态,可以得出从第i位转移到第i+1位时,原状态等价于自动机上第j个状态,现状态等价于自动机上第k个状态的概率的转移方程:

f[i+1][k]=f[i][j]/alphabet

(在这之前先把fail指针的信息整合到trie的子节点关系上即可)

特别地,当新状态为模版串末位时,我们直接转移到trie树的根节点,并累加伤害的期望值

因为状态有限,且只能由第i位转移到第i+1位。。

我们就可以用矩阵快速幂轻松地优化了!(总结点数还是比较和谐的)

AC Code

#include
#include
#include
#include
#define N 110
#define maxsiz 101
using namespace std;
struct matrix {
	int l,r;
	long double m[N][N];
}ori,tmp,f;
int ch[N][26],n,len,alphabet,fail[N],q[N],m,cnt;
char s[N];
bool boo[N];
void build_trie(int id){
	int now=0;
	for (int i=1;i<=m;i++) {
		if (!ch[now][s[i]-'a']) ch[now][s[i]-'a']=++cnt;
		now=ch[now][s[i]-'a'];
		if (boo[now]) break;
	}
	boo[now]=1;
}
void getfail(){
	int h=0,t=1;q[h]=0;
	while (h!=t) {
		int now=q[h++];if (h>maxsiz)h=0;
		int tmp=0;
		for (int i=0;imaxsiz) t=0;
		}
		else ch[now][i]=ch[fail[now]][i];
	}
	ori.m[cnt+1][cnt+1]=1;
}
void mul(matrix &x,matrix &y){
	tmp.l=x.l;tmp.r=y.r;
	memset(tmp.m,0,sizeof(tmp.m));
	for (int k=0;k>=1,mul(ori,ori)) if (len&1) mul(f,ori);
	double ans=f.m[0][cnt+1];
	printf("%.9lf",ans);
}


你可能感兴趣的:(BZOJ2553:[BeiJing2011]禁忌 AC自动机+矩阵快速幂)