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 ...
随机推荐
- 双击jar不能运行的解决方法
1.问题描述 使用eclipse导出jar.双击jar文件弹出一个内容为“a java exception has occurred”的错误警告提示! 但是在命令行用 java -jar Em ...
- boost编译配置及简单使用
boost编译配置及简单使用 1.下载 http://www.boost.org/ 2.编译: A.解压 boost_1_55_0.zip 到boost路径 B.运行 bootstrap.bat. 会 ...
- FZU2030 括号问题(dp)
Problem 2030 括号问题 Accept: 398 Submit: 753Time Limit: 1000 mSec Memory Limit : 32768 KB Proble ...
- L2-013. 红色警报 (并查集)
战争中保持各个城市间的连通性非常重要.本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报.注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不 ...
- L2-014. 列车调度 (DP)
火车站的列车调度铁轨的结构如下图所示. Figure 两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道.每趟列车从入口可以选择任意一条轨道进入,最后从出口 ...
- C++ 无边框的拖动窗口代码
按下鼠标时,记录下鼠标在窗体上的坐标, 同时用一个BOOL变量记录下鼠标左键按下的状态 弹起左键,则记录状态的布尔变量为FALSE. 处理鼠标移动事件,如果左键同时按下,则为鼠标拖动窗体运动,设置窗体 ...
- Manacher's Algorithm 马拉车算法(最长回文串)
这个马拉车算法Manacher‘s Algorithm是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性,这 ...
- 在 WinForm/WPF 下制作 Google Material Design 风格程序
国内社区没有,顺手转.WinForm: https://github.com/IgnaceMaes/MaterialSkin演示:https://www.youtube.com/watch?v=A8o ...
- firefly
firefly (9秒社团-游戏服务端开源引擎) 编辑 Firefly是免费.开源.稳定.快速扩展.能 “热更新”的分布式游戏服务器端框架,采用Python编写,基于Twisted框架开发.它包括了开 ...
- 如何使用Node.js搭建一个服务器
在node环境中运行下面的代码 "use strict"; const http = require("http"), path = require(" ...