2020牛客多校 第四场 C Count New String(广义后缀自动机)
题意等价于对\(S\)的\(|S|\)个后缀进行\(f\)操作,求这|S|个操作后的后缀的本质不同的子串个数
把每个操作后的后缀翻转后插入字典树
当所有后缀都插入字典树之后建广义后缀自动机
直接统计答案即可
#include
using namespace std;
typedef long long ll;
const int maxn=2e6;
int fa[maxn],c[maxn],tr[maxn][10],tot=0;
int ins(char ch,int pos)
{
int id=ch-'a';
if(!tr[pos][id])
{
tr[pos][id]=++tot;
fa[tot]=pos;
c[tot]=id;
}
return tr[pos][id];
}
#define Cpy(a, b) memcpy(a, b, sizeof(a))
struct Suffix_Automata
{
int maxlen[maxn], trans[maxn][10], link[maxn], Size,pos[maxn];
Suffix_Automata() { Size = 1; }
inline int Extend(int id,int Last)
{
int cur = (++Size), p;
maxlen[cur] = maxlen[Last] + 1;
for (p = Last; p && !trans[p][id]; p = link[p])
trans[p][id] = cur;
if (!p)
link[cur] = 1;
else
{
int q = trans[p][id];
if (maxlen[q] == maxlen[p] + 1)
link[cur] = q;
else
{
int clone = (++Size);
maxlen[clone] = maxlen[p] + 1;
Cpy(trans[clone], trans[q]);
link[clone] = link[q];
for (; p && trans[p][id] == q; p = link[p])
trans[p][id] = clone;
link[cur] = link[q] = clone;
}
}
return cur;
}
inline void build()
{
queueq;
for(int i=0;i<10;++i)
{
if(tr[0][i])
q.push(tr[0][i]);
}
pos[0]=1;
while(!q.empty())
{
int x=q.front();q.pop();
pos[x]=Extend(c[x],pos[fa[x]]);
for(int i=0;i<10;++i)
if(tr[x][i])q.push(tr[x][i]);
}
}
inline void cal(){
ll ans=0;
for(int i=2;i<=Size;++i)ans+=maxlen[i]-maxlen[link[i]];
printf("%lld\n",ans);
}
} sam;
char s[maxn];
int pre[maxn];
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
for (int i = len; i >= 1; i--)
{
int p = 0;
for (int j = i + 1; j <= len; j++)
{
if (s[i] > s[j]) s[j] = s[i];
else
{
p = j;
break;
}
}
int sta;
if (p == 0) sta = len;
else sta = p - 1;
pre[i] = pre[p];
for (int j = sta; j >= i; j--) pre[i] = ins(s[i], pre[i]);
}
sam.build();
sam.cal();
return 0;
}