BZOJ4566 [Haoi2016]找相同字符 字符串 SAM
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4566.html
题目传送门 - BZOJ4566
题意
给定两个字符串 $s1$ 和 $s2$ ,问有多少 $a,b,c,d$ 满足 $s1[a\cdots b] = s2[c\cdots d]$ 。
$|s1|,|s2|\leq 200000$
题解
建个广义 SAM ,然后统计一下。
模板题。
代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=200005*4; struct SAM{ int Next[26],fa,Max; }t[N]; int size,v[N][2],in[N],q[N],head,tail; char s[N]; void init(){ memset(t,0,sizeof t); memset(v,0,sizeof v); size=1,t[0].Max=-1; for (int i=0;i<26;i++) t[0].Next[i]=1; } int extend(int p,int c){ if (t[p].Next[c]&&t[p].Max+1==t[t[p].Next[c]].Max) return t[p].Next[c]; int np=++size,q,nq; t[np].Max=t[p].Max+1; for (;!t[p].Next[c];p=t[p].fa) t[p].Next[c]=np; q=t[p].Next[c]; if (t[p].Max+1==t[q].Max) t[np].fa=q; else { nq=++size; t[nq]=t[q],t[nq].Max=t[p].Max+1; t[np].fa=t[q].fa=nq; for (;t[p].Next[c]==q;p=t[p].fa) t[p].Next[c]=nq; } return np; } void build(int x){ scanf("%s",s+1); int n=strlen(s+1); for (int i=1,p=1;i<=n;i++) v[p=extend(p,s[i]-'a')][x]++; } int main(){ init(); build(0); build(1); memset(in,0,sizeof in); for (int i=2;i<=size;i++) in[t[i].fa]++; head=tail=0; for (int i=1;i<=size;i++) if (in[i]==0) q[++tail]=i; while (head<tail){ int x=q[++head]; for (int i=0;i<2;i++) v[t[x].fa][i]+=v[x][i]; if ((--in[t[x].fa])==0) q[++tail]=t[x].fa; } LL ans=0; for (int i=2;i<=size;i++) ans+=1LL*v[i][0]*v[i][1]*(t[i].Max-t[t[i].fa].Max); printf("%lld",ans); return 0; }