SPOJ 8222 NSUBSTR - Substrings【SAM上DP

本文介绍了一种基于字符串的SAM算法实现方法,该算法通过构建特殊的数据结构来解决字符串匹配问题,并提供了一个完整的C++代码示例。文章详细解释了算法的工作原理,包括节点插入、状态转移等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

试了试把SAM打个包【似乎可以优美一点…………吗?】

题目大意……大概就是给一个长度为n的字符串,输出n行,每行一个数,第i行输出长度为i的子串中,出现次数最多的是多少次……

反正right集合大小就是出现次数嘛……于是胡搞乱搞

#include<bits/stdc++.h>
#define MAXN 500057

//#define FIAZE_NAlVE

using namespace std;

struct t1{
	int son[MAXN][26],dis[MAXN],pre[MAXN];
	int lst,cnt;
	
	int siz[MAXN];
	
	void insert(int x){
		int np=++cnt, p=lst;
		dis[np]=dis[p]+1;
		lst=np;
		siz[np]=1;
		
		for(;p&&!son[p][x];p=pre[p])	son[p][x]=np;
		if(!p)	return pre[np]=1,void();
		
		int q=son[p][x];
		if(dis[q]==dis[p]+1)	return pre[np]=q,void();
		
		int nq=++cnt;
		dis[nq]=dis[p]+1;
		pre[nq]=pre[q];
		pre[q]=pre[np]=nq;
		memcpy(son[nq],son[q],sizeof son[q]);
		
		for(;p&&son[p][x]==q;p=pre[p])	son[p][x]=nq;
	}
	
	char read_s[MAXN];
	int lth_s;
	void build(){
		lst=1,cnt=1;
		scanf("%s",read_s);
		lth_s=strlen(read_s);
		for(int i=0;i<lth_s;++i)	insert(read_s[i]-97);
	}

#ifdef FIAZE_NAlVE	
	char tmp[MAXN];
	void _check_if_correct_(int now,int stp){
		for(int i=0;i<26;++i)
			if(son[now][i]){
				tmp[stp]=i+97;
				puts(tmp);
				_check_if_correct_(son[now][i],stp+1);
				tmp[stp]=' ';
			}
	}
#endif

	int v[MAXN],q[MAXN];
	int ans[MAXN];
	void init(){
		for(int i=1;i<=cnt;++i)	++v[dis[i]];
		for(int i=1;i<=lth_s;++i)	v[i]+=v[i-1];
		for(int i=1;i<=cnt;++i)	q[v[dis[i]]--]=i;
		
//		for(int i=1;i<=cnt;++i)	printf("%d ",q[i]);
//		cout<<endl;
		
		for(int i=cnt;i;--i)	siz[pre[q[i]]]+=siz[q[i]];
	}
	void calc(){
		for(int i=1;i<=cnt;++i)
			ans[dis[i]]=max(ans[dis[i]],siz[i]);
		for(int i=lth_s-1;i;--i)
			ans[i]=max(ans[i],ans[i+1]);
		for(int i=1;i<=lth_s;++i)	printf("%d\n",ans[i]);
	}
}SAM_s;



int main(){
	freopen("1.in","r",stdin);
	freopen("orz.out","w",stdout); 
	SAM_s.build();
	SAM_s.init();
	SAM_s.calc();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值