bzoj4566 / P3181 [HAOI2016]找相同字符

P3181 [HAOI2016]找相同字符

后缀自动机
(正解应是广义后缀自动机
并不会广义后缀自动机。
然鹅可以用普通的后缀自动机。
 
我们先引入一个问题:算出从一个串内取任意两个不重合子串完全相同的方案数。
显然,对于每个点$w$,$tot+=siz[w]*(siz[w]-1)/2*(len[w]-len[fa[w]])$
$siz[w]$表示该点对应子串出现次数
那么答案即为$tot_{a+b}-tot_a-tot_b$
计算$tot_{a+b}$时在$a,b$间插入一个特殊字符即可。(插入$'{'='z'+1$较方便)
attention:数组需要开n*2*2=800000大小!
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define N 800005
 6 int n; char s1[N],s2[N];
 7 long long ans,tot;
 8 struct Sam{
 9     int nxt[N][27],len[N],siz[N],fa[N];
10     int p,q,last,ed,a[N],c[N];
11     void clear(){
12         last=ed=1;
13         memset(fa,0,sizeof(fa));
14         memset(nxt,0,sizeof(nxt));
15         memset(len,0,sizeof(len));
16         memset(siz,0,sizeof(siz));
17         memset(c,0,sizeof(c));
18     }
19     void add(int c){
20         p=last; len[last=++ed]=len[p]+1; siz[ed]=1;
21         for(;p&&!nxt[p][c];p=fa[p]) nxt[p][c]=ed;
22         if(!p){fa[ed]=1; return;}
23         q=nxt[p][c];
24         if(len[q]==len[p]+1){fa[ed]=q; return;}
25         len[++ed]=len[p]+1;
26         memcpy(nxt[ed],nxt[q],sizeof(nxt[q]));
27         fa[ed]=fa[q]; fa[q]=fa[ed-1]=ed;
28         for(;nxt[p][c]==q;p=fa[p]) nxt[p][c]=ed;
29     }//裸的板子
30     void calc(){
31         for(int i=1;i<=ed;++i) ++c[len[i]];
32         for(int i=1;i<=ed;++i) c[i]+=c[i-1];
33         for(int i=1;i<=ed;++i) a[c[len[i]]--]=i;//对len进行排序代替dfs
34         for(int i=ed;i;--i){
35             int w=a[i]; siz[fa[w]]+=siz[w];
36             tot+=1ll*siz[w]*(siz[w]-1)/2*(len[w]-len[fa[w]]);//累计每个点的贡献
37         }
38     }
39 }sam;
40 void solve(char *v,int x){
41     tot=0; n=strlen(v+1); sam.clear();
42     for(int i=1;i<=n;++i) sam.add(v[i]-'a');
43     sam.calc(); ans+=tot*x;
44 }
45 int main(){
46     scanf("%s",s1+1); scanf("%s",s2+1);
47     solve(s1,-1); solve(s2,-1);
48     strcat(s1+1,"{"); strcat(s1+1,s2+1);
49     solve(s1,1); printf("%lld",ans);
50     return 0;
51 }
View Code

 

posted @ 2019-01-05 00:47  kafuuchino  阅读(160)  评论(0编辑  收藏  举报