[BOI2009] Radio Transmission 无线传输
题目描述
给你一个字符串 s 1 s_1 s1,它是由某个字符串 s 2 s_2 s2 不断自我连接形成的(保证至少重复 2 2 2 次)。但是字符串 s 2 s_2 s2 是不确定的,现在只想知道它的最短长度是多少。
输入格式
第一行一个整数 L L L,表示给出字符串的长度。
第二行给出字符串 s 1 s_1 s1 的一个子串,全由小写字母组成。
输出格式
仅一行,表示 s 2 s_2 s2 的最短长度。
样例 #1
样例输入 #1
8
cabcabca
样例输出 #1
3
提示
样例输入输出 1 解释
对于样例,我们可以利用 abc \texttt{abc} abc 不断自我连接得到 abcabcabc \texttt{abcabcabc} abcabcabc,读入的 cabcabca \texttt{cabcabca} cabcabca,是它的子串。
规模与约定
对于全部的测试点,保证 1 < L ≤ 1 0 6 1 < L \le 10^6 1<L≤106。
KMP博大精深,这题跟模板题不是一个层次的,偏向于理解,而代码长度反而短于模板题。
主要理解点:
n
−
p
[
n
]
的含义是什么?
n-p[n]的含义是什么?
n−p[n]的含义是什么?
这里先给出答案:从字符串的某一处开始到串末,和串首到某一处是完全相等的,其中最长的就是最长公共前后缀
洛谷题解讲解
本蒟蒻讲的肯定没这个好,不如直接看题解
蒟蒻讲解部分
假设一个字符串abcabcabcabc… …经过KMP的一番操作(前后缀不可能等于本串),
第一个周期和第二个周期完全相等(1 ~ 3和4 ~ 6),
第二个周期又和第三个周期完全相等(7 ~ 10和11 ~ 13)。
以此类推。
既然相等当然就可以匹配了
也就是最长公共前后缀就是第1个周期开始到第2个周期
然后是第2个周期到第3个周期
那么最长的前缀假设为1234,最长的后缀为2345,其中公共的部分就是最长公共前后缀,也就是234,其中的1与5相等,
n
−
p
[
n
]
=
一个周期
n-p[n]=一个周期
n−p[n]=一个周期
自然也就能得出上述的结论了。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+99;
int n,p[N];
char a[N];
void pre(){
int j=0;p[1]=0;
for(int i=1;i<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;
}
}
int main(){
cin>>n;
scanf("%s",a+1);
pre();
cout<<n-p[n]<<endl;
return 0;
}