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;
}

 

posted @ 2018-07-23 11:46  尹吴潇  阅读(143)  评论(0编辑  收藏  举报