【ybt高效进阶2-3-2】重复子串
发布日期:2021-05-07 06:59:33 浏览次数:16 分类:精选文章

本文共 1644 字,大约阅读时间需要 5 分钟。

重复子串

题目链接:

题目大意

给定若干个的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。

思路

这道题我们考虑用 KMP,先对这个字符串跑一次 KMP。

f a i l n fail_n failn 就代表着 1 ∼ f a i l n 1\sim fail_n 1failn 的子串跟 n − f a i l n + 1 ∼ n n-fail_n+1\sim n nfailn+1n 的子串是相等的。

那我们考虑一下要在什么情况下,才会由多个相同子字符串组成。

那我们画图来看:
在这里插入图片描述
这个是编号,并不是字符串,我们只是要假设相等的子串的位置。

假设你要变成两段,那肯定就是从中间分开。(如下图)

在这里插入图片描述
那如果要分成三段,就要三等分开,但是你只能从一个地方分开。
那我们考虑从哪里分开的时候相当于三等分开。
在这里插入图片描述
那我们要 s 1 ∼ 4 = s 5 ∼ 8 = s 9 ∼ 12 s_{1\sim4}=s_{5\sim8}=s_{9\sim12} s14=s58=s912
那你想想两份分成了 1 ∼ a 1\sim a 1a n − a + 1 ∼ n n-a+1\sim n na+1n,那对于一个小于等于 a a a 的正整数 b b b,会有 1 ∼ b 1\sim b 1b n − a + 1 ∼ n − a + b n-a+1\sim n-a+b na+1na+b 相等。
其实,如果再有一个大于等于 b b b,小于等于 a a a 的正整数 c c c,还会有 b ∼ c b\sim c bc n − a + b ∼ n − a + c n-a+b\sim n-a+c na+bna+c

那我们可以发现,我们让长度为 8 8 8 就可以了!

相交的有四个,然后分出来的两个它们的前四个和后四个都是相等的,就刚好得出了我们要的。

那如果分成四段呢?

不难想到,就是让长度为 9 9 9

总结一下规律,当序列长度为 n n n,你要分成 x x x 段时, f a i l n fail_n failn 就应该要是 n − n x n-\dfrac{n}{x} nxn

(当然, n n n 一定是 x x x 的倍数,不然都分不了)

那我们看一下当 f a i l n fail_n failn 已经确定的时候,要分成几段。

那就是 n n − f a i l n \dfrac{n}{n-fail_n} nfailnn,移项可得。
当然,你也可以知道,前提是 n n n n − f a i l n n-fail_n nfailn 的倍数,否则就只能分成一份。(就是一个整个)

代码

#include
#include
using namespace std;int an, ans, fail[1000001], j;char a[1000001];int main() { scanf("%s", a + 1); an = strlen(a + 1); while (an != 1 || a[1] != '.') { //KMP j = 0; for (int i = 2; i <= an; i++) { while (j && a[i] != a[j + 1]) j = fail[j]; if (a[i] == a[j + 1]) j++; fail[i] = j; } if (an % (an - fail[an]) == 0) printf("%d\n", an / (an - fail[an]));//可以分段 else printf("1\n");//分不了段,就只能一整个 scanf("%s", a + 1); an = strlen(a + 1); } return 0;}
上一篇:【JavaFX】ListView
下一篇:使用tar命令

发表评论

最新留言

关注你微信了!
[***.104.42.241]2025年04月04日 02时06分52秒