2023ACM暑假训练day 9 后缀自动机SAM

DAY 9 后缀自动机SAM

训练地址:传送门

训练情况简介

2023-07-07 09:20:38 星期五
早上和下午都在学后缀自动机的相关概念,有点简单又有点难
下午,学了个板子,过了A题
A 题,求子串出现次数大于1的子串的长度乘以次数的最大值
有点difficult?或者说就是,不知道怎么运用啦~有空再补

A 题

题意:
求子串出现次数大于1的子串的长度乘以次数的最大值
思路:
利用后缀自动机寻找子串及其出现次数。那么对于子串出现次数,我们考虑由后缀链构成的母树,叶子节点子串仅出现一次,不做考虑,仅考虑所有的分支节点,取每个节点的值的最大即可。因为我们可以知道一个后缀链意味着什么,意味着先前串继承出现一次。那对于每个子串,后面连了多少个分支,就出现了多少次,还有本身出现一次。可以利用dfs来求解。(可能表述有误,但就是这个意思)
代码:

//>>>Qiansui
#include<map>
#include<set>
#include<list>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
	return x*f;
}

using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*
后缀自动机模板题
难,记住板子~
*/
const int maxm=1e6+5,inf=0x3f3f3f3f,mod=998244353,N=maxm<<1;
string ss;
int tot=1,np=1;
int fa[N],ch[N][26],len[N];
int ans,cnt[N];
vector<int> e[N];

void insert(int c){
	int p=np;
	np=++tot;
	len[np]=len[p]+1;
	cnt[np]=1;

	for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;

	if(p==0) fa[np]=1;// 1
	else{
		int q=ch[p][c];
		if(len[q]==len[p]+1)// 2
			fa[np]=q;
		else{// 3
			int nq=++tot;
			len[nq]=len[p]+1;
			fa[nq]=fa[q];
			fa[q]=nq;
			fa[np]=nq;
			for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
		}
	}
	return ;
}

void dfs(int u){
	for(auto v:e[u]){
		dfs(v);
		cnt[u]+=cnt[v];
	}
	if(cnt[u]>1) ans=max(ans,cnt[u]*len[u]);
	return ;
}

void solve(){
	cin>>ss;
	for(auto a:ss) insert(a-'a');
	for(int i=2;i<=tot;++i){
		e[fa[i]].push_back(i);
	}
	dfs(1);
	cout<<ans<<'\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
//	cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

题意:

思路:

posted on 2023-07-07 09:21  Qiansui  阅读(13)  评论(0编辑  收藏  举报