Spoj REPEATS 后缀自动机+set
REPEATS - Repeats
链接:http://www.spoj.com/problems/REPEATS
题意:求S串中某个子串连续循环次数最多的次数。
想法:
从暴力开始,枚举所有串,求出这些串的最小循环节长度,算出连续循环次数。
如何求一个串S的最小循环节长度:即next表示这个串最长后缀与前缀相等的长度,最小循环节长度=S.length-next。
KMP可以解决next,于是O(n^2)暴力求出答案。然后优化一下。

上图ans=(len+(x-y))/(x-y)。
在SAM一个节点上,以其{right}为右端点长度为[min,max]的串都相等。那么对应上图,{right}中距离最小的两个点x,y.ans=(max+|x-y|)/|x-y|。
用平衡树维护{right},再启发式合并。
总O(nlog^2n)
#include<cstdio>
#include<cstring>
#include<set>
const int len(),INF();
struct SamNode{int nx[],pre,step;}sam[len*+];
std::set<int>RBT[len*+];int size[len*+],rt[len*+];
std::set<int>::iterator ii,ti;
int top=,root=,now=,last,lastson;
int cnt[len+],p[len*+],mn[len*+];
void insert(int x)
{
last=now;now=++top;
sam[now].step=sam[last].step+;
size[now]=;mn[now]=INF;rt[now]=now;
RBT[now].insert(sam[now].step);
for(;!sam[last].nx[x]&&last;last=sam[last].pre)
sam[last].nx[x]=now;
if(!last)sam[now].pre=root;
else
{
lastson=sam[last].nx[x];
if(sam[lastson].step==sam[last].step+)sam[now].pre=lastson;
else
{
sam[++top]=sam[lastson];
sam[top].step=sam[last].step+;
mn[top]=INF;rt[top]=top;size[top]=;
sam[now].pre=sam[lastson].pre=top;
for(;sam[last].nx[x]==lastson&&last;last=sam[last].pre)
sam[last].nx[x]=top;
}
}
}
int T,n,ans;char ch[];
void swap(int &a,int &b){if(a==b)return;a^=b;b^=a;a^=b;}
int min(int a,int b){return a>b?b:a;}
int max(int a,int b){return a<b?b:a;}
void union_set(int x,int y)
{
if(size[rt[x]]<size[rt[y]])swap(rt[x],rt[y]);
int val;
for(ii=RBT[rt[y]].begin();ii!=RBT[rt[y]].end();ii++)
{
val=*(ii);
RBT[rt[x]].insert(val);
ti=RBT[rt[x]].find(val);
if(ti!=RBT[rt[x]].begin())
{
ti--;mn[rt[x]]=min(mn[rt[x]],val-*(ti));ti++;
}
if(ti!=RBT[rt[x]].end())
{
ti++;
if(ti!=RBT[rt[x]].end())mn[rt[x]]=min(mn[rt[x]],*(ti)-val);
}
size[rt[x]]++;
}
RBT[rt[y]].clear();
}
void total()
{
for(int i=;i<=n;i++)cnt[i]=;
for(int i=;i<=top;i++)cnt[sam[i].step]++;
for(int i=;i<=n;i++)cnt[i]+=cnt[i-];
for(int i=top;i>=;i--)p[cnt[sam[i].step]--]=i;
for(int i=top;i>=;i--)
{
ans=max(ans,(sam[p[i]].step+mn[rt[p[i]]])/mn[rt[p[i]]]);
union_set(sam[p[i]].pre,p[i]);
}
RBT[rt[]].clear();
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(sam,,sizeof(sam));
top=,root=,now=;ans=;
mn[]=INF;rt[]=;size[]=;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%s",ch);
insert(ch[]-'a');
}
total();
printf("%d\n",ans);
}
return ;
}
Spoj REPEATS 后缀自动机+set的更多相关文章
- SPOJ NSUBSTR (后缀自动机)
SPOJ NSUBSTR Problem : 给一个长度为n的字符串,要求分别输出长度为1~n的子串的最多出现次数. Solution :首先对字符串建立后缀自动机,在根据fail指针建立出后缀树,对 ...
- SPOJ LCS 后缀自动机
用后缀自动机求两个长串的最长公共子串,效果拔群.多样例的时候memset要去掉. 解题思路就是跟CLJ的一模一样啦. #pragma warning(disable:4996) #include< ...
- SPOJ - LCS 后缀自动机入门
LCS - Longest Common Substring A string is finite sequence of characters over a non-empty finite set ...
- SPOJ LCS 后缀自动机找最大公共子串
这里用第一个字符串构建完成后缀自动机以后 不断用第二个字符串从左往右沿着后缀自动机往前走,如能找到,那么当前匹配配数加1 如果找不到,那么就不断沿着后缀树不断往前找到所能匹配到当前字符的最大长度,然后 ...
- SPOJ 7258 (后缀自动机)
转载:http://hzwer.com/4492.html 给一个长度不超过90000的串S,每次询问它的所有不同子串中,字典序第K小的,询问不超过500个. 搞出后缀自动机 dp处理出每个点往下走能 ...
- 长度为x的本质不同的串的出现次数 SPOJ - NSUBSTR 后缀自动机简单应用
题意: 长度为x的本质不同的串的出现次数 题解: 先处理出每一个节点所对应的子串出现的次数 然后取max就好了 #include <set> #include <map> #i ...
- 多个串的最长公共子串 SPOJ - LCS2 后缀自动机
题意: 求多个串的最长公共子串 这里用的是O(n)的后缀自动机写法 我后缀数组的专题有nlog(n)写法的 题解: 对于其中的一个串建立后缀自动机 然后对于后缀自动机上面的每一个节点求出每一个节点最长 ...
- SPOJ REPEATS 后缀数组
题目链接:http://www.spoj.com/problems/REPEATS/en/ 题意:首先定义了一个字符串的重复度.即一个字符串由一个子串重复k次构成.那么最大的k即是该字符串的重复度.现 ...
- SPOJ - SUBLEX 后缀自动机
SPOJ - SUBLEX 思路:求第k大字串,求出sam上每个节点开始能识别多少字串,然后从起点开始跑就好啦. #include<bits/stdc++.h> #define LL lo ...
随机推荐
- hdu1853 Cyclic Tour (二分图匹配KM)
Cyclic Tour Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/65535 K (Java/Others)Total ...
- sqlserver2012——变量declare
1.声明变量病定义类型 赋值操作 ) set @name='小明' select @name 使用select进行赋值 ) select @name='李明' seelelct @name
- E20190418-hm
distinct adj. 明显的,清楚的; 卓越的,不寻常的; 有区别的; 确切的; predicate vt. 断言,断定; 宣布,宣讲; 使基于; n. 谓语; 述语;
- static_cast、dynamic_cast、const_cast和reinterpret_cast总结
转自:http://www.jellythink.com/archives/205 前言 这篇文章总结的是C++中的类型转换,这些小的知识点,有的时候,自己不是很注意,但是在实际开发中确实经常使用的. ...
- ue4 enable input
actor: enable input 这个可以使多个actor接收输入 pawn: possese pawn使用enable input是不生效的 貌似不允许多个pawn同时接收输入,可以考虑直接 ...
- Linux ssh 密钥对登陆设置
SSH通过密钥连接 ssh -i ~/miyao.pem root@server_ip 密钥权限要设置为仅root用户读写 chmod 600 ~/miyao.pem 密钥可添加到系统里,以后连接可除 ...
- C 语言实例 - 阶乘
C 语言实例 - 阶乘 一个正整数的阶乘(英语:factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1.自然数n的阶乘写作n!. n!=×××...×n.阶乘亦可以递归方式定义:!=, ...
- PAT甲级——1111 Online Map (单源最短路经的Dijkstra算法、priority_queue的使用)
本文章同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90041078 1111 Online Map (30 分) ...
- LVM逻辑卷基本概念以及相关操作
一.LVM概念 LVM(Logical Vloume Manager):它是linux环境下对磁盘进行管理的一种机制,正常挂载的磁盘在磁盘资源快要耗尽时,无法动态拉伸增加资源,或由于特殊情况需要动态缩 ...
- 这个匿名对象没有实现IComparable接口
https://www.cnblogs.com/felixnet/p/5193086.html https://docs.microsoft.com/zh-cn/dotnet/api/system.i ...