Kmp(求字符串公共循环节数目)——Common Divisors ( CodeForces 182D )

  • 题目链接:
    http://codeforces.com/contest/182/problem/D

  • 分析:
    题意为给出两个字符串,求其公共循环节的数目,那么首先要求出其公共最小循环节!这里需要用到Kmp算法中的SetNext()函数来求循环节。

  • 关键步骤:

1.SetNext()函数:(将第一个重复位之前的所有位的值赋为-1,然后第一个重复位从0开始,之后匹配失败也赋值为0)

void SetNext(char s[])
{
        int j=-1,i;
        Next[0]=-1;
        int len=strlen(s);
        for(i=1;i<len;i++)
        {
            while(j>=0&&s[i]!=s[j+1])
                j=Next[j];
            if(s[i]==s[j+1])
                j++;
            Next[i]=j;
        }
}

2.求字符串最短循环节:(与上面SetNext函数一块用)

    void recycle (char s[])
    {
        int len = str(s);
        int length = 0;//最短循环节长度
        if(len % ( len - Next[len-1]-1 ) ==0)
            length = len - Next[len-1];
        else
            length = len;
        //创建最短循环节字符串
        for(int i=0;i<length;i++)
        {
            rec[i] = s[i];
        }
  • 题解:
    求出最短循环节长度length后,再求出原来两个字符串长度的最大公约数max,然后不断叠加length,直到length大于max,过程中如果叠加得到的结果能整除两个字符串长度就说明这也是一个公共循环节。

  • AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>

using namespace std;

char a[112345];
char b[112345];
char c[112345];

int Next[112345];
int M,N;
int NN;
int cc;
void SetNext(char s[])
{
        int j=-1,i;
        Next[0]=-1;
        int len=strlen(s);
        for(i=1;i<len;i++)
        {
            while(j>=0&&s[i]!=s[j+1])
                j=Next[j];
            if(s[i]==s[j+1])
                j++;
            Next[i]=j;
        }
}
void circle(char s[])
{
    cc=0;
    if( NN%(NN-Next[NN-1]-1) == 0 )
        cc = NN-Next[NN-1]-1;
    else
        cc = NN;
    for(int i=0;i<cc;i++)
        c[i] = s[i];

}

int Kmp(char x[],char y[])
{
    int cnt = 0;
    int i=0,j=0;
    while(i<N)
    {

        if(x[i]==y[j])
            i++, j++;
        else
            return -1;
        if(j==cc)
        {
            j = 0;
            cnt++;
        }
    }
    return cnt;
}

int gcd(int a, int b)
{
    return b==0? a : gcd(b, a%b);
}

int main()
{
    scanf("%s", a);
    scanf("%s", b);


    int tmp;
    if(strlen(a)>=strlen(b))
    {
        N = strlen(a);
        NN = strlen(b);
        SetNext(b);
        circle(b);
        tmp = Kmp(a, c);
    }
    else
    {
        N = strlen(b);
        NN = strlen(a);
        SetNext(a);
        circle(a);
        tmp = Kmp(b, c);
    }


    int ans=0;
    if(tmp>0)
    {
        int mm = gcd(N,NN);
        int d = cc;
        while(cc<=mm)
        {
            if( N%cc == 0 && NN %cc == 0)
            {
                ans++;
            }
            cc+=d;
        }
    }
    cout << ans << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值