bzoj4566: [Haoi2016]找相同字符
题解:
跟找最长公共子串几乎差不多的方法在后缀自动机上跑
找到一个匹配点,ans+=sum[x]
其中sum[x]=sum[fa]+(len[x]-len[fa[x]])*size[x]
另外一个比较通用的方法
是建立广义后缀自动机
那么每个点的贡献是(len[x]-len[fa[x]])*size1[x]*size2[x]
后缀数组也可解
将两个串相连
枚举最小值单调栈维护就可以了
代码(广义后缀自动机):
*对建立过程的特判以后再研究一下
#include <bits/stdc++.h> #define ll long long #define rint register int #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) using namespace std; const int N=3e6; char s[N]; int size[N][2],len[N],ch[N][26]; int lst=1,node=1,t[N],a[N],fa[N],pl; void extend(int c) { int f=lst; if (ch[f][c]&&len[ch[f][c]]==len[f]+1) { lst=ch[f][c]; return; } int p=++node; lst=p; len[p]=len[f]+1; //size[p][pl]=1; while (f&&!ch[f][c]) ch[f][c]=p,f=fa[f]; if (!f) { fa[p]=1; return;}; int x=ch[f][c],y=++node; if (len[f]+1==len[x]) {fa[p]=x; node--;return;}; len[y]=len[f]+1; fa[y]=fa[x]; fa[x]=fa[p]=y; memcpy(ch[y],ch[x],sizeof(ch[x])); while (f&&ch[f][c]==x) ch[f][c]=y,f=fa[f]; } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); cin>>s; int l=strlen(s); rep(i,1,l) extend(s[i-1]-'a'),size[lst][0]++; lst=1; pl=1; cin>>s; l=strlen(s); rep(i,1,l) extend(s[i-1]-'a'),size[lst][1]++; rep(i,1,node) t[len[i]]++; rep(i,1,node) t[i]+=t[i-1]; rep(i,1,node) a[t[len[i]]--]=i; dep(j,node,1) { int i=a[j]; size[fa[i]][1]+=size[i][1]; size[fa[i]][0]+=size[i][0]; } // cout<<node<<endl; ll ans=0; rep(i,1,node) if (fa[i]) ans+=1ll*(len[i]-len[fa[i]])*size[i][1]*size[i][0]; cout<<ans<<endl; return 0; }