SPOJ NSUBSTR

题意:

给出一个字符串,求这个字符串长度为1-n的子串的最大出现次数;

字符串长度<=250000;


题解:

几天没更新,水一发后缀自动机的题解吧;

首先定义后缀自动机的的right集合大小,就是该结点代表的状态能拓展到的子串种类;

那么对于长度为x的子串的答案就是所有长度>=x的结点的right值的最大值;

right值是不能再构建自动机时增量维护的,所以只能在构建这个后缀自动机之后再O(n)搞一遍;

具体就是从反向后缀树的叶子开始,定义每个关键节点的right初始都为1,然后顺着求出所有节点的子树和就可以了;

然后再用right[x]更新f[len[x]],扫一遍让f[i]=max(f[i],f[i+1]);

时间复杂度O(n);

然而后缀自动机的构建依然是基本靠背的代码。。

而且大概后缀自动机顺便建出来的反向后缀树比那个识别后缀的本体要有用得多。。真是233


代码:


#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 260000
#define S 26
using namespace std;
char str[N];
int f[N];
namespace SAM
{
	int son[N<<1][S],len[N<<1],pre[N<<1];
	int in[N<<1],right[N<<1];
	int tot,last;
	queue<int>q;
	int newnode()
	{
		tot++;
		memset(son[tot],0,sizeof(int)*S);
		pre[tot]=len[tot]=0;
		return tot;
	}
	void init()
	{
		tot=0;
		last=newnode();
	}
	void Insert(int x)
	{
		int p,np=newnode();
		right[np]=1;
		len[np]=len[last]+1;
		for(p=last;p&&!son[p][x];p=pre[p])
			son[p][x]=np;
		if(!p)
			pre[np]=1;
		else
		{
			int q=son[p][x];
			if(len[q]==len[p]+1)
				pre[np]=q;
			else
			{
				int nq=newnode();
				pre[nq]=pre[q];
				len[nq]=len[p]+1;
				memcpy(son[nq],son[q],sizeof(int)*S);
				pre[np]=pre[q]=nq;
				for(;son[p][x]==q;p=pre[p])
					son[p][x]=nq;
			}
		}
		last=np;
	}
	void Build()
	{
		int x,i;
		for(i=1;i<=tot;i++)
		{
			in[pre[i]]++;
		}
		for(i=1;i<=tot;i++)
		{
			if(!in[i])
				q.push(i);
		}
		while(!q.empty())
		{
			x=q.front(),q.pop();
			in[pre[x]]--;
			right[pre[x]]+=right[x];
			if(!in[pre[x]])
				q.push(pre[x]);
		}
	}
	void calc(int n)
	{
		for(int i=1;i<=tot;i++)
			f[len[i]]=max(f[len[i]],right[i]);
		for(int i=n-1;i>=1;i--)
			f[i]=max(f[i],f[i+1]);
	}
}
int main()
{
	int n,m,i,j,k;
	scanf("%s",str+1);
	n=strlen(str+1);
	SAM::init();
	for(i=1;i<=n;i++)
	{
		SAM::Insert(str[i]-'a');
	}
	SAM::Build();
	SAM::calc(n);
	for(i=1;i<=n;i++)
	{
		printf("%d\n",f[i]);
	}
	return 0;
}



洛谷的SPOJ需要注册一个SPOJ账号并进行绑定才能进行交题。您可以按照以下步骤进行注册: 1. 打开洛谷网站(https://www.luogu.com.cn/)并登录您的洛谷账号。 2. 在网站顶部导航栏中找到“题库”选项,将鼠标悬停在上面,然后选择“SPOJ”。 3. 在SPOJ页面上,您会看到一个提示,要求您注册SPOJ账号并进行绑定。点击提示中的链接,将会跳转到SPOJ注册页面。 4. 在SPOJ注册页面上,按照要求填写您的用户名、密码和邮箱等信息,并完成注册。 5. 注册完成后,返回洛谷网站,再次进入SPOJ页面。您会看到一个输入框,要求您输入刚刚注册的SPOJ用户名。输入用户名后,点击“绑定”按钮即可完成绑定。 现在您已经成功注册并绑定了SPOJ账号,可以开始在洛谷的SPOJ题库上刷题了。祝您顺利完成编程练习!\[1\]\[2\] #### 引用[.reference_title] - *1* *3* [(洛谷入门系列,适合洛谷新用户)洛谷功能全解](https://blog.csdn.net/rrc12345/article/details/122500057)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [luogu p7492 序列](https://blog.csdn.net/zhu_yin233/article/details/122051384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值