SPOJ REPEATS Repeats (后缀数组 + RMQ:子串的最大循环节)题解
题意:
给定一个串\(s\),\(s\)必有一个最大循环节的连续子串\(ss\),问最大循环次数是多少
思路:
我们可以知道,如果一个长度为\(L\)的子串连续出现了两次及以上,那么必然会存在\(s[0]、s[L]、s[2L] \cdots s[L * k]\)中至少有两个连续的位置是相同的,然后看字母\(s[L * i]和s[L * (i + 1)]\)往前往后最多能匹配多远,记住总长度\(len\),那么最大循环次数为\((len / L) + 1\)。
参考:
SPOJ 687. Repeats(后缀数组)
代码:
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 50000 + 5;
const int INF = 0x3f3f3f3f;
const ull seed = 11;
const int MOD = 1e9 + 7;
using namespace std;//下标从0开始
int str[maxn]; //str[n]赋值一个最小值0,其他大于0
int t1[maxn], t2[maxn], c[maxn];
int sa[maxn]; //排名为i的后缀下标
int rk[maxn]; //后缀下标为i的排名
int height[maxn]; //sa[i]与sa[i - 1]的LCP
int mm[maxn];
int dp[maxn][30];
bool cmp(int *r, int a, int b, int l){return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *str, int n, int m){n++;int i, j, p, *x = t1, *y = t2;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[i] = str[i]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;for(j = 1; j <= n; j <<= 1){p = 0;for(i = n - j; i < n; i++) y[p++] = i;for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[y[i]]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];swap(x, y);p = 1; x[sa[0]] = 0;for(i = 1; i < n; i++)x[sa[i]] = cmp(y, sa[i - 1], sa[i], j)? p - 1 : p++;if(p >= n) break;m = p;}int k = 0;n--;for(i = 0; i <= n; i++) rk[sa[i]] = i;for(i = 0; i < n; i++){if(k) k--;j = sa[rk[i] - 1];while(str[i + k] == str[j + k]) k++;height[rk[i]] = k;}
}
void initRMQ(int n){mm[0] = -1;for(int i = 1; i <= n; i++){dp[i][0] = height[i];mm[i] = ((i & (i - 1)) == 0)? mm[i - 1] + 1 : mm[i - 1];}for(int j = 1; j <= mm[n]; j++)for(int i = 1; i + (1 << j) - 1 <= n; i++)dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}
int RMQ(int L, int R){int k = mm[R - L + 1];return min(dp[L][k], dp[R - (1 << k) + 1][k]);
}
int LCP(int i, int j){ //求后缀i和j的LCP最长公共前缀int L = rk[i], R = rk[j];if(L > R) swap(L, R);L++;return RMQ(L, R);
}int main(){int T;scanf("%d", &T);while(T--){int n;scanf("%d", &n);for(int i = 0; i < n; i++){char ss[2];scanf("%s", ss);str[i] = ss[0] - 'a' + 1;}str[n] = 0;da(str, n, 3);initRMQ(n);int ans = 1;for(int i = 1; i < n; i++){for(int j = 0; j + i < n; j += i){int len = LCP(j, j + i);int times = len / i + 1;int pos = j - (i - len % i);if(pos >= 0){len = LCP(pos, pos + i);times = max(times, len / i + 1);}ans = max(ans, times);}}printf("%d\n", ans);}return 0;
}
转载于:https://www.cnblogs.com/KirinSB/p/11262768.html
SPOJ REPEATS Repeats (后缀数组 + RMQ:子串的最大循环节)题解相关推荐
- 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过
题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...
- SPOJ 7258 SUBLEX 后缀数组_二分答案_前缀和
SPOJ 7258 SUBLEX 后缀数组_二分答案_前缀和 Code: #include <cstdio> #include <algorithm> #include < ...
- hdu 2459 (后缀数组+RMQ)
题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...
- URAL - 1297 Palindrome(后缀数组+RMQ)
题目链接:点击查看 题目大意:给出一个字符串,求出最长的回文子串 题目分析:如果用以往的方法求,不可避免的都需要枚举所有子串,时间复杂度就已经到达了O(n),而后缀数组可以通过O(n)预处理后得到所有 ...
- hdu 5008 Boring String Problem(后缀数组+rmq)
题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...
- HDU - 6194 string string string(后缀数组+RMQ+容斥)
题目链接:点击查看 题目大意:给出一个字符串和一个数字 k,问字符串中出现次数恰好等于 k 次的字串有多少个 题目分析:在跑完后缀数组后,我们可以用sa数组求解,具体做法是枚举起点,找长度为 k 的s ...
- HDU - 4552 怪盗基德的挑战书(后缀数组+RMQ/KMP+dp)
题目链接:点击查看 题目大意:给出一个字符串,统计每个前缀在字符串中出现的次数之和 题目分析:可以直接先用后缀数组跑出来height,再用RMQ跑出来任意两个后缀的height,我们可以将题意转换为求 ...
- HDU 6194 string string string 后缀数组 + RMQ(线段树)
传送门:HDU6194 题意:问给定字符串中有多少种出现k次的子串. 思路:首先想到后缀数组经典问题,求出现不少于k次的子串的最大长度,类似的这题肯定就是在height数组上搞事情啦. 将height ...
- URAL 题目1297. Palindrome(后缀数组+RMQ求最长回文子串)
1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just ...
- POJ - 3693 Maximum repetition substring(后缀数组+RMQ)
题目链接:点击查看 题目大意:给出一个字符串,求出字符串中 重复次数最多的连续重复子串 ,如果有多个答案,输出字典序最小的 题目分析:又是一个模板题,这里放一个大佬的博客,讲的很清楚: https:/ ...
最新文章
- Git011--分支管理策略
- PLSQL_性能优化系列04_Oracle Optimizer优化器
- 阅读《Android 从入门到精通》(29)——四大布局
- 第三次学JAVA再学不好就吃翔(part82)--泛型
- springmvc ztree 实现权限菜单的展示
- 2010年5月系统集成项目管理工程师上午试卷参考答案(讨论版)
- mysql 修改表名的方法:sql语句
- 普中51控制火焰传感器_传感器检测:以后,电动车充电会变成这样
- 头条三面: String.valueOf、toString()、(String)强转,有啥区别?
- composer切换源_composer的安装 及 常用命令(切换源等)
- 学渣的c#复习手记 类 一
- html插入swf自动播放,html嵌入播放器,flv视频播放器 Flvplayer.swf 可自动播放参数说明...
- 台式计算机常用的网卡类型,台式机无线网卡如何查看型号
- java毕业生设计学生管理部门信息共享交流系统计算机源码+系统+mysql+调试部署+lw
- 软件信息安全杂志《Information Security》2011年11月期下载
- C#加密和解密PDF文件
- 工作内存与主内存是什么,硬件层面的存储架构是什么样,线程的实现原理是什么
- activated钩子函数
- LRUCache算法
- Displaytag 使用简介