hdu 3746 Cyclic Nacklace KMP(失配函数)

题意:

给定一个字符串,现在要求在字符串末尾补上最少的单词数,使得该字符串成为带有循环节的字符串。输出最少需要加的单词数。(循环节:例如:ababab,ab为循环节,共k=3次循环,题意要求是k>=2)

题解:

我们又要用到KMP算法中的失配函数f[i],其表示的意思就是f[i]位置之前的字符串,即f[i]长的字符串前缀与i位置之前f[i]长的字符串相等。我们将字符串每i-f[i]个字符分一组,分成m组,每组记为ci,那么由于前面的性质,我们发现ci=c(i+1)。所以只有最后的剩余部分n%(n-f[n])是不在这个分组内,但由于性质这部分字符串必定是ci的前缀,所以只要补齐(n-f[n])-n%(n-f[n])个就能使得字符串带循环节了。

特殊情况,f[n]=0的时候,说明完全没有匹配的地方,需要在加n个字符,其实也可以用上述公式得到;另一种是n%(n-f[n])==0,则原本就是带循环节的,不需要在添加字符了。





代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
using namespace std;

const int maxn=1e5+10;
char a[maxn];
int f[maxn];
void getFail(char *a,int *f,int n)
{
    int i,j;
    f[0]=f[1]=0;
    for(i=1;i<n;i++)
    {
        j=f[i];
        while(j&&a[i]!=a[j])j=f[j];
        f[i+1]=a[i]==a[j]?j+1:0;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k,n;
        scanf("%s",a);
        n=strlen(a);
        getFail(a,f,n);
        k=n-f[n];
        if(f[n]==0)printf("%d\n",n);
        else if(n%k==0)printf("0\n");
        else printf("%d\n",k-n%k);
    }
    return 0;
}


你可能感兴趣的:(KMP)