4566: [Haoi2016]找相同字符
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 128 Solved: 75
[Submit][Status][Discuss]
Description
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两
个子串中有一个位置不同。
Input
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
Output
输出一个整数表示答案
Sample Input
aabb
bbaa
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 }