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 8222 Substrings(NSUBSTR),后缀自动机

spoj 8222  Substrings f[i]指长度为i的串出现次数的最大值。这里的不同出现指,可以有重复串,只要起始位置不同就视为不同的出现。 求f[1]..f[lenth]。   怎...
  • asdfgh0308
  • asdfgh0308
  • 2014年08月17日 18:25
  • 955

SPOJ NSUBSTR Substrings 后缀自动机

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

SPOJ NSUBSTR

题意: 给出一个字符串,求这个字符串长度为1-n的子串的最大出现次数; 字符串长度 题解: 几天没更新,水一发后缀自动机的题解吧; 首先定义后缀自动机的的right集合大小,就是该结...
  • ww140142
  • ww140142
  • 2015年11月18日 23:01
  • 1182

SPOJ NSUBSTR Substrings

SPOJ NSUBSTR Substrings后缀自动机SAM题意给一个字符串长度n,求他所有长度为k的子串中出现最多的串的出现次数。要求输出所有k的答案。思路SAM,拓扑排序统计每个状态的endpo...
  • xzxxzx401
  • xzxxzx401
  • 2017年09月26日 21:57
  • 55

[SPOJ8222]NSUBSTR - Substrings

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

SPOJ - NSUBSTR

#include #include #include #include #include using namespace std; struct suffix_automaton{ int fa,s...
  • liufengwei1
  • liufengwei1
  • 2017年09月17日 19:40
  • 78

SPOJ NSUBSTR

给出一个长25×10425 \times 10 ^ 4 的字符串,定义f(x)f(x)为所有的长xx的子串中出现次数最多的那个的出现次数,求f(1),f(2)...f(strlen)f(1),f(2)...
  • a1s4z5
  • a1s4z5
  • 2016年09月06日 09:42
  • 103

SPOJ NSUBSTR(后缀自动机)

(http://acm.hust.edu.cn/vjudge/contest/view.action?cid=106071#problem/C) 题意:问s,分别输出1~len的子串最多出现次数。 ...
  • r_clover
  • r_clover
  • 2016年03月02日 19:05
  • 136

【后缀自动机】 SPOJ NSUBSTR

CLJ论文上有讲这题。。。子串出现的次数就是节点的right集合的大小。。。。 #include #include #include #include #include #incl...
  • blankcqk
  • blankcqk
  • 2015年03月04日 14:13
  • 281

后缀自动机1002 SPOJ NSUBSTR

题意: 求长度为i的最多的出现次数 思路: 对于Sam上的每个节点保存匹配串的最长匹配长度 然后再传给父亲节点就行了 #include #include #include #include #...
  • qq_27925701
  • qq_27925701
  • 2016年08月08日 09:55
  • 166
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:SPOJ NSUBSTR
举报原因:
原因补充:

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