BZOJ 2553: [BeiJing2011]禁忌
现在越写越觉得AC自动机之类的好简单233,明明之前觉得超难的说
首先我们容易想到一个关于划分的贪心,对于所有要划分的禁忌的字符串,划分点必然是它们的右端点
那么也就意味着如果我们在AC自动机上走,那么每遇到一个字符串的结尾就可以把贡献\(+1\)
所以我们容易想出一个DP,令\(f_{i,j}\)表示前\(i\)个字符,走到自动机上的\(j\)点的概率和是多少,由于每次的贡献是\(1\),因此这个总概率就是期望
转移的话根据下一个点的情况讨论,如果不是终止节点就直接转移,否则转移到根节点,并且累加上当前的概率
这样复杂度太高,但我们一眼就能看出每次转移其实是相通的,那么我们用矩乘优化
这里的矩阵构造应该是非常显然的吧,由于我们要构造的矩阵是一步转移的概率,因此只用考虑每个点和它的子节点即可
注意最后的概率是一个和的形式,因此要多开一维来记录和,每次转移到根节点的时候同时也转移到这一维去
写一发交一下WA了,随手改个long double
上去就过了233
#include<cstdio>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=80;
struct Matrix
{
int n,m; long double mat[N][N];
inline Matrix(CI N=0,CI M=0)
{
n=N; m=M; memset(mat,0,sizeof(mat));
}
inline long double* operator [] (CI x) { return mat[x]; }
friend inline Matrix operator * (Matrix A,Matrix B)
{
Matrix C(A.n,B.m); for (RI i=0,j,k;i<C.n;++i)
for (j=0;j<C.m;++j) for (k=0;k<A.m;++k)
C[i][j]+=A[i][k]*B[k][j]; return C;
}
friend inline Matrix operator ^ (Matrix A,int p)
{
Matrix T(A.n,A.n); for (RI i=0;i<T.n;++i) T[i][i]=1;
for (;p;p>>=1,A=A*A) if (p&1) T=A*T; return T;
}
}a; int n,len,m; char s[N];
class AC_Automation
{
private:
struct ac_node
{
int ch[26],fail;
}node[N]; int tot,q[N]; bool end[N];
public:
#define next(x,y) node[x].ch[y]
#define fail(x) node[x].fail
inline void insert(char *s)
{
int len=strlen(s+1),now=0; for (RI i=1;i<=len;++i)
{
if (!next(now,s[i]-'a')) next(now,s[i]-'a')=++tot;
now=next(now,s[i]-'a');
}
end[now]=1;
}
inline void get_fail(void)
{
RI H=0,T=0,i; for (i=0;i<m;++i) if (next(0,i)) q[++T]=next(0,i);
while (H<T)
{
int now=q[++H],to; for (i=0;i<m;++i)
if (!(to=next(now,i))) next(now,i)=next(fail(now),i);
else end[to]|=end[fail(q[++T]=to)=next(fail(now),i)];
}
}
inline long double solve(void)
{
long double p=1.0/m; for (RI i=0,j;i<=tot;++i) for (j=0;j<m;++j)
if (end[next(i,j)]) a[i][tot+1]+=p,a[i][0]+=p; else a[i][next(i,j)]+=p;
a[tot+1][tot+1]=1; a.n=a.m=tot+2; a=a^len; return a[0][tot+1];
}
#undef next
#undef fail
}AC;
int main()
{
RI i; for (scanf("%d%d%d",&n,&len,&m),i=1;i<=n;++i)
scanf("%s",s+1),AC.insert(s); AC.get_fail();
return printf("%.7Lf",AC.solve()),0;
}
辣鸡老年选手AFO在即