SPOJ NSUBSTR

原创 2015年11月18日 23:01:11

题意:

给出一个字符串,求这个字符串长度为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 - NSUBSTR Substrings

SPOJ - NSUBSTR Substrings(后缀自动机+拓扑排序+DP)

[SPOJ8222]NSUBSTR - Substrings

后缀自动机
  • hbhcy98
  • hbhcy98
  • 2016年04月04日 11:19
  • 310

SPOJ NSUBSTR Substrings

Description You are given a string S which consists of 250000 lowercase latin letters at most. ...

SPOJ 8222 NSUBSTR(SAM)

这几天看了N多论文研究了下后缀自动机,刚开始蛋疼的看着极短的代码和clj的论文硬是看不懂,后来结合其他几篇论文研究了下,总算是明白了一些 推荐文章http://blog.sina.com.cn/s/...

SPOJ 题目 8222 NSUBSTR - Substrings(后缀自动机+DP求子串出现最大次数)

NSUBSTR - Substrings no tags  You are given a string S which consists of 250000 lowercase latin...

【后缀自动机】 SPOJ NSUBSTR

CLJ论文上有讲这题。。。子串出现的次数就是节点的right集合的大小。。。。 #include #include #include #include #include #incl...

SPOJ NSUBSTR Substrings 后缀自动机

题目大意: 就是现在给出一个长度不超过25W的字符串S, 定义F(x)表示字符串S中长度为x的子串出现的最多次数, 例如“ababa"中F(1) = 3 (“a”出现了3次), F(2) = 2 (...

spoj 8222 Substrings(NSUBSTR),后缀自动机

spoj 8222  Substrings f[i]指长度为i的串出现次数的最大值。这里的不同出现指,可以有重复串,只要起始位置不同就视为不同的出现。 求f[1]..f[lenth]。   怎...

spoj4491 莫比乌斯反演

  • 2015年08月22日 12:48
  • 263KB
  • 下载

spoj做题表格

  • 2012年10月21日 19:58
  • 133KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:SPOJ NSUBSTR
举报原因:
原因补充:

(最多只允许输入30个字)