bzoj 4566 [Haoi2016]找相同字符SA

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 }

 

posted @ 2018-01-12 20:31  Kaiser-  阅读(208)  评论(0编辑  收藏  举报