bzoj 4566: [Haoi2016]找相同字符
Description
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两
个子串中有一个位置不同。
Input
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
Output
输出一个整数表示答案
Sample Input
aabb
bbaa
bbaa
Sample Output
10
后缀自动机: 用类似于求两个串的lcs一样的方法,先对一个串建立sam,然后另外一个串在sam上进行匹配。 好像用广义的后缀自动机也可以做。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int const N=200000+10; 4 int f[N<<1],ch[N<<1][26],tot,ls,sz[N<<1],num[N],sa[N<<1]; 5 long long cnt[N<<1],len[N<<1]; 6 char s1[N],s2[N]; 7 void add(int c){ 8 int p=ls; 9 int np=ls=++tot; 10 len[np]=len[p]+1; 11 sz[np]=1; 12 for(;p&&!ch[p][c];p=f[p]) ch[p][c]=np; 13 if(!p) f[np]=1; 14 else { 15 int q=ch[p][c]; 16 if(len[q]==len[p]+1) f[np]=q; 17 else { 18 int nq=++tot; 19 len[nq]=len[p]+1; 20 memcpy(ch[nq],ch[q],sizeof(ch[q])); 21 f[nq]=f[q]; 22 f[q]=f[np]=nq; 23 for(;p&&ch[p][c]==q;p=f[p]) 24 ch[p][c]=nq; 25 } 26 } 27 } 28 int main(){ 29 scanf("%s%s",s1,s2); 30 int n=strlen(s1); 31 tot=ls=1; 32 for(int i=0;i<n;i++) 33 add(s1[i]-'a'); 34 for(int i=1;i<=tot;i++) num[len[i]]++; 35 for(int i=1;i<=n;i++) num[i]+=num[i-1]; 36 for(int i=1;i<=tot;i++) sa[num[len[i]]--]=i; 37 for(int i=tot;i>=2;i--){ 38 int x=sa[i]; 39 int fa=f[x]; 40 sz[fa]+=sz[x]; 41 } 42 for(int i=2;i<=tot;i++){ 43 int x=sa[i]; 44 int fa=f[x]; 45 cnt[x]=sz[x]*(len[x]-len[fa])+cnt[fa]; 46 } 47 int p=1,tmp=0; 48 long long ans=0; 49 for(int i=0;i<n;i++){ 50 int c=s2[i]-97; 51 if(ch[p][c]) { 52 tmp++; p=ch[p][c]; 53 ans+=(tmp-len[f[p]])*sz[p]+cnt[f[p]]; 54 }else { 55 while (p && !ch[p][c]) p=f[p]; 56 if(!p) { 57 p=1;tmp=0; 58 }else { 59 tmp=len[p]+1; 60 p=ch[p][c]; 61 ans+=(tmp-len[f[p]])*sz[p]+cnt[f[p]]; 62 } 63 } 64 } 65 cout<<ans<<endl; 66 return 0; 67 }