[hdu7081]Pty loves book

建立ac自动机,令$S_{x}$为以根到$x$的路径所构成的字符串以及$L_{x}=|S_{x}|,W_{x}=\sum_{1\le i\le m,t_{i}为S_{x}的后缀}w_{i}$,那么不难得到有$W_{x}=\sum_{1\le i\le m,t_{i}=S_{x}}w_{i}+W_{fail_{x}}$,即可预处理出$W$

进一步的,令$pos(s)$为在其中查询$s$得到的最终节点,则有$f(s)=\sum_{i=1}^{|s|}W_{pos(s[1,i])}$

接下来,考虑再求出$F_{x}=\sum_{i=1}^{L_{x}}f(S_{x}[i,L_{x}])^{5}$,对于其中$i>L_{x}-L_{fail_{x}}$的部分即为$F_{fail_{x}}$,而剩下的部分即为$\sum_{i=1}^{L_{x}-L_{fail_{x}}}f(S_{x}[i,L_{x}])^{5}$,将其记为$G_{x}$

关于$G_{x}$,显然$f(S_{x}[i,L_{x}])=f(S_{x}[i,L_{x}))+W_{pos(S_{x}[i,L_{x}])}$,并特判$i=1$时的贡献(即$x$到根路径$W$之和的5次方),对于其他情况后者即$W_{fail_{x}}$

关于前者,即从$x$的父亲$fa$开始不断走到$fail_{fa}$直至$fail_{x}$的父亲为止的$G_{fa}$之和,但注意其中还多算了$i=1$时的答案,即去掉$f(S_{x}[1,L_{x}))+W_{fail_{x}}$

另外由于是5次方,需要求出$G_{x,p}=\sum_{i=1}^{L_{x}-L_{fail_{x}}}f(S_{x}[i,L_{x}])^{p}$​,展开后即有
$$
G_{x,p}=\sum_{i=0}^{p}{p\choose i}W_{fail_{x}}^{i}\sum_{fa}G_{fa,p-i}+(\sum_{y在x到根路径上}W_{y})^{p}-(\sum_{y在x的父亲到根路径上}W_{x}+W_{fail_{x}})^{p}
$$
最终,不妨初始将$s$也加入自动机中,那么答案即$pos(s)$到根路径的$F$之和,可以计算

总复杂度为$o(5^{2}|s|)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 1000005
 4 #define mod 1000000007
 5 #define ll long long
 6 queue<int>q;
 7 int V,t,n,m,x,ans,C[6][6],fail[N],w[N],sum[N],G[N][6],F[N],ch[N][26];
 8 char s[N];
 9 int New(){
10     int k=++V;
11     w[k]=0;
12     memset(G[k],0,sizeof(G[k])); 
13     memset(ch[k],0,sizeof(ch[k]));
14     return k;
15 }
16 void add(int x){
17     int k=1,l=strlen(s);
18     for(int i=0;i<l;i++){
19         if (!ch[k][s[i]-'a'])ch[k][s[i]-'a']=New();
20         k=ch[k][s[i]-'a'];
21     }
22     w[k]=(w[k]+x)%mod;
23 }
24 int main(){
25     for(int i=0;i<6;i++){
26         C[i][0]=C[i][i]=1;
27         for(int j=1;j<i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
28     }
29     scanf("%d",&t);
30     while (t--){
31         scanf("%s%d",s,&m);
32         V=ans=0,n=strlen(s);
33         New(),add(0);
34         for(int i=1;i<=m;i++){
35             scanf("%s%d",s,&x);
36             add(x);
37         }
38         fail[1]=1;
39         q.push(1);
40         while (!q.empty()){
41             int k=q.front();
42             q.pop();
43             for(int i=0;i<26;i++)
44                 if (ch[k][i]){
45                     if (k==1)x=1;
46                     else{
47                         x=fail[k];
48                         while ((x>1)&&(!ch[x][i]))x=fail[x];
49                         if (ch[x][i])x=ch[x][i];
50                     }
51                     fail[ch[k][i]]=x;
52                     w[ch[k][i]]=(w[ch[k][i]]+w[x])%mod;
53                     sum[ch[k][i]]=(sum[k]+w[ch[k][i]])%mod;
54                     q.push(ch[k][i]);
55                 }
56         }
57         q.push(1);
58         while (!q.empty()){
59             int k=q.front();
60             q.pop();
61             for(int i=0;i<26;i++)
62                 if (ch[k][i]){
63                     x=ch[k][i];
64                     int s1=1,s2=1;
65                     for(int p=1;p<6;p++){
66                         s1=(ll)s1*sum[x]%mod,s2=(ll)s2*(sum[k]+w[fail[x]])%mod;
67                         G[x][p]=(s1-s2+mod)%mod;
68                     }
69                     if (fail[x]==1)G[x][0]=1;
70                     for(int p=0;p<6;p++){
71                         int s=1;
72                         for(int j=0;j<=p;j++){
73                             for(int fa=k;(fa!=1)&&(ch[fa][i]!=fail[x]);fa=fail[fa])G[x][p]=(G[x][p]+(ll)C[p][j]*s%mod*G[fa][p-j])%mod;
74                             s=(ll)s*w[fail[x]]%mod;
75                         }
76                     }
77                     F[x]=(F[fail[x]]+G[x][5])%mod;
78                     q.push(x);
79                 }
80         }
81         for(int i=1;i<=n;i++)ans=(ans+F[i+1])%mod;
82         printf("%d\n",ans);
83     }
84     return 0;
85 } 
View Code

 

posted @ 2021-08-25 16:26  PYWBKTDA  阅读(151)  评论(0编辑  收藏  举报