HihoCoder #1449 : 后缀自动机三·重复旋律6

传送门
还是后缀自动机的模板题,还是计算每个等价类的出现次数,我终于明白为什么那个 f 数组不能在 dfs 的时候赋初值了,因为从父节点中扩展出去的 nq 节点是不能为父节点贡献的。
还缩了缩代码的长度,可以发现 sam 比 acam 还要好写,但是难理解的多。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
const int N=1e6+10;
char s[N];
struct SAM{
	char *s;
	int g[N*2][26],len[N*2],fa[N*2],f[N*2],last,tot,ans[N];
	int head[N*2],nxt[N*2],to[N*2],total;
	void add(int u,int v){to[++total]=v;nxt[total]=head[u];head[u]=total;}
	int newnode(){++tot;memset(g[tot],0,sizeof(g[tot]));len[tot]=fa[tot]=f[tot]=0;return tot;}
	void add(int c){
		int p=last,np=last=newnode();
		len[np]=len[p]+1;f[np]=1;
		for(;p&&!g[p][c];p=fa[p]) g[p][c]=np;
		if(!p) {fa[np]=1;return;}
		int q=g[p][c];
		if(len[q]==len[p]+1) {fa[np]=q;return;}
		int nq=newnode();memcpy(g[nq],g[q],sizeof(g[nq]));fa[nq]=fa[q];len[nq]=len[p]+1;
		fa[np]=fa[q]=nq;
		for(;p&&g[p][c]==q;p=fa[p]) g[p][c]=nq;
	}
	void dfs(int u){
		for(int i=head[u];i;i=nxt[i]) dfs(to[i]),f[u]+=f[to[i]];
	}
	void init(char *_s){
		s=_s;last=newnode();
		int strlen=0;
		for(int i=1;s[i];i++) add(s[i]-'a'),strlen++;
		for(int i=2;i<=tot;i++) add(fa[i],i);
		dfs(1);
		for(int i=1;i<=tot;i++) ans[len[i]]=max(ans[len[i]],f[i]);
		for(int i=strlen;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
	}
}sam;

int main(){
	scanf("%s",s+1);
	sam.init(s);
	for(int i=1;s[i];i++) printf("%d
",sam.ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/12618839.html