bzoj4566 [Haoi2016]找相同字符
Description
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。
Input
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
Output
输出一个整数表示答案
Sample Input
aabb
bbaa
bbaa
Sample Output
10
正解:后缀自动机+后缀树。
做完以后看网上的题解,才发现我的做法是最笨的。。
这道题前缀和后缀一样,所以我们可以不用反向构后缀自动机了。
然后我的$naive$做法是先在两个串中间弄一个分隔符,然后再对这个大串构一个后缀自动机,算出贡献。
但是这样会算重,具体来说就是一个子串和它自己那个串中的子串算了一次答案。
于是我们再对两个小串分别构后缀自动机,减去相应贡献就行了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 6 using namespace std; 7 8 char s1[200010],s2[200010]; 9 int len1,len2; 10 ll ans; 11 12 il int gi(){ 13 RG int x=0,q=1; RG char ch=getchar(); 14 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 15 if (ch=='-') q=-1,ch=getchar(); 16 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 17 return q*x; 18 } 19 20 struct Big_Suffix_Automaton{ 21 22 #define N (800010) 23 24 struct edge{ int nt,to; }g[N]; 25 26 int ch[N][27],fa[N],sz[N],l[N],head[N],la,tot,num; 27 28 il void init(){ la=++tot; return; } 29 30 il void add(RG int c){ 31 RG int np=++tot,p=la; la=np,l[np]=l[p]+1,sz[np]=1; 32 for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np; 33 if (!p){ fa[np]=1; return; } RG int q=ch[p][c]; 34 if (l[q]==l[p]+1) fa[np]=q; else{ 35 RG int nq=++tot; l[nq]=l[p]+1; 36 fa[nq]=fa[q],fa[q]=fa[np]=nq; 37 memcpy(ch[nq],ch[q],sizeof(ch[q])); 38 for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 39 } 40 return; 41 } 42 43 il void insert(RG int from,RG int to){ 44 g[++num]=(edge){head[from],to},head[from]=num; return; 45 } 46 47 il void build(){ 48 for (RG int i=2;i<=tot;++i) insert(fa[i],i); 49 return; 50 } 51 52 il void dfs(RG int x,RG int fg){ 53 for (RG int i=head[x],v;i;i=g[i].nt){ 54 v=g[i].to,dfs(v,fg); 55 ans+=1LL*fg*l[x]*sz[x]*sz[v],sz[x]+=sz[v]; 56 } 57 return; 58 } 59 60 #undef N 61 62 }SAM0; 63 64 struct Small_Suffix_Automaton{ 65 66 #define N (400010) 67 68 struct edge{ int nt,to; }g[N]; 69 70 int ch[N][27],fa[N],sz[N],l[N],head[N],la,tot,num; 71 72 il void init(){ la=++tot; return; } 73 74 il void add(RG int c){ 75 RG int np=++tot,p=la; la=np,l[np]=l[p]+1,sz[np]=1; 76 for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np; 77 if (!p){ fa[np]=1; return; } RG int q=ch[p][c]; 78 if (l[q]==l[p]+1) fa[np]=q; else{ 79 RG int nq=++tot; l[nq]=l[p]+1; 80 fa[nq]=fa[q],fa[q]=fa[np]=nq; 81 memcpy(ch[nq],ch[q],sizeof(ch[q])); 82 for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 83 } 84 return; 85 } 86 87 il void insert(RG int from,RG int to){ 88 g[++num]=(edge){head[from],to},head[from]=num; return; 89 } 90 91 il void build(){ 92 for (RG int i=2;i<=tot;++i) insert(fa[i],i); 93 return; 94 } 95 96 il void dfs(RG int x,RG int fg){ 97 for (RG int i=head[x],v;i;i=g[i].nt){ 98 v=g[i].to,dfs(v,fg); 99 ans+=1LL*fg*l[x]*sz[x]*sz[v],sz[x]+=sz[v]; 100 } 101 return; 102 } 103 104 #undef N 105 106 }SAM1,SAM2; 107 108 int main(){ 109 #ifndef ONLINE_JUDGE 110 freopen("same.in","r",stdin); 111 freopen("same.out","w",stdout); 112 #endif 113 scanf("%s%s",s1+1,s2+1); 114 len1=strlen(s1+1),len2=strlen(s2+1); 115 SAM0.init(),SAM1.init(),SAM2.init(); 116 for (RG int i=1;i<=len1;++i) 117 SAM0.add(s1[i]-'a'),SAM1.add(s1[i]-'a'); 118 SAM0.add(26); 119 for (RG int i=1;i<=len2;++i) 120 SAM0.add(s2[i]-'a'),SAM2.add(s2[i]-'a'); 121 SAM0.build(),SAM1.build(),SAM2.build(); 122 SAM0.dfs(1,1),SAM1.dfs(1,-1),SAM2.dfs(1,-1); 123 cout<<ans; return 0; 124 }