bzoj 3277 & bzoj 3473,bzoj 2780 —— 广义后缀自动机

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277

https://www.lydsy.com/JudgeOnline/problem.php?id=3473

广义后缀自动机:https://www.cnblogs.com/HocRiser/p/9580478.html

像 Trie 树一样处理了重复节点;

基数排序后DP,f 数组求的直接是这个点及其祖先的答案;

开 2e5 就可以,因为每次加入一个字符最多新增2个点。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=2e5+5;
int n,K,cnt=1,go[xn][30],len[xn],fa[xn],vis[xn],tot[xn],lst;
ll f[xn]; 
string s[xn];
int work(int p,int w)
{
  int nq=++cnt,q=go[p][w]; len[nq]=len[p]+1;
  memcpy(go[nq],go[q],sizeof go[q]);
  fa[nq]=fa[q]; fa[q]=nq;
  for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
  return nq;
}
int ext(int p,int w)
{
  if(go[p][w])
    {
      int q=go[p][w]; 
      if(len[q]==len[p]+1)return q; return work(p,w);
    }
  int np=++cnt; len[np]=len[p]+1;
  for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
  if(!p)fa[np]=1;
  else
    {
      int q=go[p][w];
      if(len[q]==len[p]+1)fa[np]=q;
      else fa[np]=work(p,w);
    }
  return np;
}
int tax[xn],q[xn],l[xn];
void rsort()
{
  for(int i=1;i<=cnt;i++)tax[len[i]]++;
  for(int i=1;i<=cnt;i++)tax[i]+=tax[i-1];
  for(int i=cnt;i;i--)q[tax[len[i]]--]=i;
}
char dc[xn];
int main()
{
  scanf("%d%d",&n,&K);
  for(int i=1;i<=n;i++)
    {
      scanf("%s",dc); s[i]=string(dc); l[i]=strlen(dc); lst=1;
      for(int j=0;j<l[i];j++)lst=ext(lst,s[i][j]-'a');
    }
  for(int i=1;i<=n;i++)
    {
      int nw=1;
      for(int j=0;j<l[i];j++)
    {
      nw=go[nw][s[i][j]-'a'];
      for(int p=nw;p&&vis[p]!=i;p=fa[p])vis[p]=i,tot[p]++;
    }
    }
  rsort();
  for(int i=1,x;i<=cnt;i++)
    f[x=q[i]]=f[fa[x]]+(tot[x]>=K?len[x]-len[fa[x]]:0);//
  for(int i=1;i<=n;i++)
    {
      ll ans=0; int nw=1;
      for(int j=0;j<l[i];j++)
    nw=go[nw][s[i][j]-'a'],ans+=f[nw];
      printf("%lld ",ans);
    }
  puts(""); return 0;
}
View Code

 

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2780

几乎完全一样,但忘记写 lst=1 呆了半小时...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=2e5+5;
int n,m,cnt=1,fa[xn],l[xn],go[xn][30],len[xn],tot[xn],vis[xn],lst;
char dc[xn]; string s[xn];
int work(int p,int w)
{
  int nq=++cnt,q=go[p][w]; len[nq]=len[p]+1;
  memcpy(go[nq],go[q],sizeof go[q]);
  fa[nq]=fa[q]; fa[q]=nq;
  for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
  return nq;
}
int ext(int p,int w)
{
  if(go[p][w])
    {
      int q=go[p][w];
      if(len[q]==len[p]+1)return q; return work(p,w);
    }
  int np=++cnt; len[np]=len[p]+1;
  for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
  if(!p)fa[np]=1;
  else
    {
      int q=go[p][w];
      if(len[q]==len[p]+1)fa[np]=q;
      else fa[np]=work(p,w);
    }
  return np;
}
int main()
{
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++)
    {
      scanf("%s",dc); l[i]=strlen(dc); s[i]=string(dc); lst=1;//lst=1!!
      for(int j=0;j<l[i];j++)lst=ext(lst,s[i][j]-'a');
    }
  for(int i=1;i<=n;i++)
    {
      int nw=1;
      for(int j=0;j<l[i];j++)
    {
      nw=go[nw][s[i][j]-'a'];
      for(int p=nw;p&&vis[p]!=i;p=fa[p])vis[p]=i,tot[p]++;
    }
    }
  for(int i=1;i<=m;i++)
    {
      scanf("%s",dc); int lth=strlen(dc),nw=1;
      for(int j=0;j<lth;j++)nw=go[nw][dc[j]-'a'];
      printf("%d\n",tot[nw]);
    }
  return 0;
}
View Code

 

posted @ 2019-01-19 09:19  Zinn  阅读(203)  评论(0编辑  收藏  举报