[BZOJ4566][HAOI2016]找相同字符(SAM)

4566: [Haoi2016]找相同字符

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 950  Solved: 550
[Submit][Status][Discuss]

Description

给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两
个子串中有一个位置不同。

Input

两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母

Output

输出一个整数表示答案

Sample Input

aabb
bbaa

Sample Output

10

HINT

Source

[Submit][Status][Discuss]

后缀数组+单调栈可以做,但是后缀数组的超长模板加上单调栈的超多细节,想想就复杂。

对于热爱DP或码力不够的选手,SAM则是最佳选择。

给两个式子自己体会什么意思,很好理解。(tmp表示当前匹配上的长度)

sum[i]=sum[fa[i]]+(l[i]-l[fa[i]])*right[i],ans+=sum[fa[p]]+(tmp-l[fa[p]])*right[p]

radixsort然后拓扑DP即可,模板又打错了。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=400100;
 9 char s1[N],s2[N];
10 int n,m,p,lst=1,np,cnt=1,mx[N],right[N],fa[N],son[N][26],q[N],c[N];
11 ll ans,sum[N];
12 
13 void ext(int c){
14     p=lst; lst=np=++cnt; mx[np]=mx[p]+1; right[np]++;
15     while (!son[p][c] && p) son[p][c]=np,p=fa[p];
16     if (!p) fa[np]=1;
17     else{
18         int q=son[p][c];
19         if (mx[q]==mx[p]+1) fa[np]=q;
20         else{
21             int nq=++cnt; mx[nq]=mx[p]+1;
22             memcpy(son[nq],son[q],sizeof(son[q]));
23             while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
24             fa[nq]=fa[q]; fa[q]=fa[np]=nq;
25         }
26     }
27 }
28 
29 void radix(){
30     rep(i,0,n) c[i]=0;
31     rep(i,1,cnt) c[mx[i]]++;
32     rep(i,1,n) c[i]+=c[i-1];
33     for (int i=cnt; i; i--) q[c[mx[i]]--]=i;
34     for (int i=cnt; i; i--) right[fa[q[i]]]+=right[q[i]];
35     rep(i,1,cnt) sum[q[i]]=sum[fa[q[i]]]+(mx[q[i]]-mx[fa[q[i]]])*right[q[i]];
36 }
37 
38 void solve(){
39     int tmp=0; p=1;
40     rep(i,1,m){
41         int c=s2[i]-'a';
42         if (son[p][c]) p=son[p][c],tmp++;
43         else{
44             while (p && !son[p][c]) p=fa[p];
45             if (!p) p=1,tmp=0; else tmp=mx[p]+1,p=son[p][c];
46         }
47         ans+=sum[fa[p]]+1ll*(tmp-mx[fa[p]])*right[p];
48     }
49 }
50 
51 int main(){
52     freopen("bzoj4566.in","r",stdin);
53     freopen("bzoj4566.out","w",stdout);
54     scanf("%s",s1+1); n=strlen(s1+1);
55     scanf("%s",s2+1); m=strlen(s2+1);
56     rep(i,1,n) ext(s1[i]-'a');
57     radix(); solve(); printf("%lld\n",ans);
58     return 0;
59 }

 

posted @ 2018-04-16 16:45  HocRiser  阅读(190)  评论(0编辑  收藏  举报