题目描述
给定若干个长度小于等于10^6的字符串,询问每个字符串最多由多少个相同的子串重复连接而成。如:ababab,最多由3个ab连接而成。
输入输出格式
输入格式
若干行,每行一个字符串。
当读入到“.”时结束程序。
输出格式
若干行,为对应的答案。
输入输出样例
输入样例
abcd
aaaa
ababab
.
输出样例
1
4
3
题解
这道题可以用字符串hash或kmp来做。
主要就是要将这道题转换成求最长前缀满足同为后缀。
假设在s[1...n]中,s[1...i]为前缀且s[n-i+1...n]为后缀,那么当i>=n-i+1时,s[1...n-i]=s[n-i+1...n-i+1+n-i]=...=s[i+1][n],继续推下去,可以证得当i|n时,i就是其中相同子串中的一个,求出最长的i即可得出结果。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #define MAX_N 1000000 using namespace std; int n; const unsigned long long b = 128; char s[MAX_N | 1]; unsigned long long p[MAX_N | 1], h[MAX_N | 1]; int main() { p[0] = 1; for(register int i = 1; i < MAX_N; ++i) { p[i] = p[i - 1] * b; } int op; while(scanf("%s", s)) { op = 0; n = strlen(s); if(n == 1 && s[0] == '.') break; h[0] = s[0]; for(register int i = 1; i < n; ++i) { h[i] = h[i - 1] * b + s[i]; } for(register int i = 1; i < n; ++i) { if(h[n - i - 1] == h[n - 1] - h[i - 1] * p[n - i]) { if(n % i) continue; printf("%d\n", n / i); op = 1; break; } } if(!op) printf("1\n"); } return 0; }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #define MAX_N 1000000 using namespace std; int n; char a[MAX_N | 1]; int p[MAX_N | 1]; int main() { while(scanf("%s", a) && (a[0] ^ '.')) { n = strlen(a); p[0] = -1; for(register int i = 0, j = -1; i + 1 < n; ++i) { while(j >= 0 && (a[i + 1] ^ a[j + 1])) j = p[j]; if(a[i + 1] == a[j + 1]) ++j; p[i + 1] = j; } if(n % (n - p[n - 1] - 1)) printf("1\n"); else printf("%d\n", n / (n - p[n - 1] - 1)); } return 0; }