kmp周期性循环节(Cyclic Nacklace HDU - 3746)

这篇博客探讨了如何使用Next数组来处理字符串的循环性质。首先解释了Next数组的概念,即它用于找到字符串的最小循环节。接着,通过两个编程题目展示了如何运用这个概念。题目1要求在不改变字符串内部结构的情况下,找到构建循环字符串所需的最少附加字符数。题目2则要求计算给定字符串的循环次数。当字符串长度能被Next数组计算出的循环节整除时,循环次数为字符串长度除以循环节;否则,循环次数为1。这两个题目都强调了Next数组在字符串处理中的应用。

知识点:考察对next数组的理解:周期性字符串循环节长度 ans 是 n−next[n] ,也可以理解为 n-next 的前缀是最小覆盖子串 ,而当前提为n% ans==0&&next[n] !=0时,循环次数是 n/ans 。

(一般只用到next,不用kmp)

题目1

题意:给你一串字符串。可以在这个字符串左右加上任意字符,使最后求得的字符串可以构成循环。

思路:

用前缀数组可以求得初始字符串的最小循环节。
最小循环节=(原字符串长度-末尾前缀数组值)
然后进行讨论:

如果最小循环节=原子符串长度.说明末尾前缀数组值为0.说明原串中,只能通过复制一次原串得到目标字符串。 ans=原串长度
如果原串长度%最小循环节=0.说明可以通过循环原串中某前缀就可以构成原串,原串已经完成循环。 ans=0
如果不是上面两种情况。说明原串中,有部分不在循环中。可以求得这部分长度为最小循环节-原串长度%最小循环节。我们加上这部分就可以构成循环,满足条件。** ans=最小循环节-原串长度%最小循环节
 

#include<bits/stdc++.h>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e5+5;
ll nexts[manx];
ll n,m,ans,t;
string p,s;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>t;
    while(t--)
    {
        cin>>p;
        m=p.size();
        getnexts();
        ll len=m-nexts[m];
        if(len!=m && m%len==0) cout<<0<<endl;
        else cout<<len-m%len<<endl;
    }
    return 0;
}

题目2

题意:给一个字符串,求循环个数

#include<string>
#include<iostream>
#include<cstdio>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;
ll nexts[manx];
ll n,m,ans,t;
string p,s;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    while(cin>>p)
    {
        if(p[0]=='.') break;
        m=p.size();
        getnexts();
        ll len=m-nexts[m];
        if(len!=m && m%len==0 ) cout<<m/len<<endl;
        else cout<<1<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值