Luogu P4070 [SDOI2016]生成魔咒

题意:求本质不同的子串数。

\(SA\)

\(SAM+DP\)

答案即为路径条数。

我们设 \(f[u]\) 表示从 \(u\) 出发的路径条数:\(f[u]=1+\sum_{(u,v,ch)} f[v]\) ,其中 \(1\) 代表空串。

最后答案即为 \(f[0]-1\)

\(SAM+parent树\)

每个子串只会出现一次,并且每个点的 \(sz\) 即为 \(maxlen[u]-minlen[u]\)

答案为 \(\sum len[u]-len[fa[u]]\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<unordered_map>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} 
const int N=100010;
int n,tot=1,lst=1;
int fa[N],len[N];
ll ans;
unordered_map<int,int> c[N];
inline void add(int ch) {
  R p=lst,np=lst=++tot;
  len[np]=len[p]+1;
  for(;p&&!c[p].count(ch);p=fa[p]) c[p][ch]=np;
  if(!p) fa[np]=1;
  else {
    R q=c[p][ch];;
    if(len[q]==len[p]+1) fa[np]=q;
    else {
      R nq=++tot;
      c[nq]=c[q];
      fa[nq]=fa[q],len[nq]=len[p]+1;
      fa[q]=fa[np]=nq;
      for(;p&&c[p].count(ch)&&c[p][ch]==q;p=fa[p]) c[p][ch]=nq;
    }
  }
  printf("%lld\n",ans+=len[np]-len[fa[np]]);
}
inline void main() {
  n=g();
  for(R i=1;i<=n;++i) add(g());
}
} signed main() {Luitaryi::main(); return 0;}

2019.01.09

posted @ 2020-01-10 17:43  LuitaryiJack  阅读(105)  评论(0编辑  收藏  举报