1. 程式人生 > >bzoj 4566 [Haoi2016]找相同字符SA

bzoj 4566 [Haoi2016]找相同字符SA

枚舉 不同 tar esc ems printf 字符 第一個 height

4566: [Haoi2016]找相同字符

Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 128 Solved: 75
[Submit][Status][Discuss]

Description

給定兩個字符串,求出在兩個字符串中各取出一個子串使得這兩個子串相同的方案數。兩個方案不同當且僅當這兩 個子串中有一個位置不同。

Input

兩行,兩個字符串s1,s2,長度分別為n1,n2。1 <=n1, n2<= 200000,字符串中只有小寫字母

Output

輸出一個整數表示答案

Sample Input

aabb
bbaa

Sample Output

10 從大到小掃描height數組,合並相鄰後綴,因為從大到小枚舉,所以當前塊中的貢獻就是第一個串的後綴數*第二個串的後綴數*當前枚舉的height。用並查集維護即可。 算了,學了後綴自動機在來切吧。
 1 #include<cstring>
 2 #include<cmath>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cstdio>
 6 
 7 #define ll long long
 8
#define N 200007 9 using namespace std; 10 11 int n,fa[N]; 12 int cnta[N<<1],cntb[N<<1],sa[N<<1],rk[N<<2],a[N<<1],b[N<<1],tsa[N<<1],height[N<<1],g[N<<1],f[N<<1],A[N<<1],B[N<<1]; 13 char s1[N],s2[N],s[N*2]; 14 15 void Get_SA()
16 { 17 for (int i=0;i<=256;i++)cnta[i]=0; 18 for (int i=1;i<=n;i++)cnta[(int)s[i]]++; 19 for (int i=1;i<=256;i++)cnta[i]+=cnta[i-1]; 20 for (int i=n;i>=1;i--)sa[cnta[(int)s[i]]--]=i; 21 rk[sa[1]]=1; 22 for (int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]); 23 for (int i=1;rk[sa[n]]!=n;i<<=1) 24 { 25 for (int j=1;j<=n;j++)a[j]=rk[j],b[j]=rk[j+i]; 26 for (int j=0;j<=n;j++)cnta[j]=cntb[j]=0; 27 for (int j=1;j<=n;j++)cnta[a[j]]++,cntb[b[j]]++; 28 for (int j=1;j<=n;j++)cnta[j]+=cnta[j-1],cntb[j]+=cntb[j-1]; 29 for (int j=n;j>=1;j--)tsa[cntb[b[j]]--]=j; 30 for (int j=n;j>=1;j--)sa[cnta[a[tsa[j]]]--]=tsa[j]; 31 rk[sa[1]]=1; 32 for (int j=2;j<=n;j++) 33 rk[sa[j]]=rk[sa[j-1]]+(a[sa[j]]!=a[sa[j-1]]||b[sa[j]]!=b[sa[j-1]]); 34 } 35 } 36 void Get_Height() 37 { 38 int len=0; 39 for (int i=1;i<=n;i++) 40 { 41 if (len)len--; 42 while(s[i+len]==s[sa[rk[i]-1]+len])len++; 43 height[rk[i]]=len; 44 } 45 } 46 bool cmp(int x,int y){return height[x]>height[y];} 47 int find(int x) 48 { 49 if (f[x]!=x)f[x]=find(f[x]); 50 return f[x]; 51 } 52 int main() 53 { 54 scanf("%s",s1+1);int len1=strlen(s1+1); 55 scanf("%s",s2+1);int len2=strlen(s2+1); 56 n=len1+len2+1; 57 for (int i=1;i<=n;i++) 58 if (i==len1+1){s[i]=(char)27;continue;} 59 else s[i]=(i<=len1)?s1[i]-a+1:s2[i-len1-1]-a+1; 60 Get_SA(); 61 Get_Height(); 62 /*for (int i=1;i<=n;i++) 63 cout<<height[i]<<" "; 64 cout<<endl;*/ 65 for (int i=1;i<=n;i++) 66 { 67 g[i]=i+1; 68 f[i]=i; 69 if (sa[i]<=len1)A[i]=1; 70 if (sa[i]>len1+1)B[i]=1; 71 } 72 sort(g+1,g+n,cmp); 73 ll ans=0; 74 for (int i=1;i<=n-1;i++) 75 { 76 int x=find(g[i]),y=find(g[i]-1); 77 ans+=((ll)A[y]*B[x]+(ll)A[x]*B[y])*height[g[i]]; 78 A[y]+=A[x],B[y]+=B[x]; 79 f[x]=y; 80 } 81 printf("%lld",ans); 82 }

bzoj 4566 [Haoi2016]找相同字符SA