HDU 3746 Cyclic Nacklace(KMP:补齐循环节)
http://acm.hdu.edu.cn/showproblem.php?pid=3746
题意:
给你一个串,要你在串头或尾添加最少的字符,使得该串至少有2个循环节,问你最少需要加几个字符.
分析:
首先要明白:如果一个串需要至少添加x(x>=0)个字符才能是有>=2个循环节的串,那么我可以只在串末尾添加,不需要去串头添加.(比如串cabc,循环节是abc,我可以在尾部添加ab即可.)
首先如果原始串已经有至少两个循环节就不必添加.当f[m]>0&&m%(m-f[m])==0时,不必添加.(结合之前的KMP循环节题目看看是不是这样.)
现在假设条件 f[m]>0&&m%(m-f[m])==0 不成立的时候呢?
重要结论:不论串S是不是循环的,如果想要S是一个循环串的话,那么它的最小循环节长度一定是len-f[len]. 其中len是串S的长度.
即不论S是不完整的循环串还是完整的循环串,len-f[len]一定是串S中去除末尾残缺部分之后,存在的最小循环节长度.现在来例证一下:
假设f[len]=0,那么是不是该串完全没有由部分子串构成最小循环节呢?是的.
只要一个串是上面的形式a或b,那么就不可能f[len]=0.
只要f[len]=0 (类似上面的形式c),那么它一定是单独成循环节,需要添加len个字符.
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXM=100000+100;
int f[MAXM],m;
char P[MAXM];
void getFail(char *P,int *f)
{
f[0]=f[1]=0;
for(int i=1;i<m;i++)
{
int j=f[i];
while(j && P[i]!=P[j]) j=f[j];
f[i+1]= (P[i]==P[j])?j+1:0;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",P);
m=strlen(P);
getFail(P,f);
if(f[m]==0)
{
printf("%d\n",m);
continue;
}
if(m%(m-f[m])==0) printf("0\n");
else
{
int len1=m-f[m];
printf("%d\n",len1-m%len1);
}
}
return 0;
}