1468:OKR-Periods of Words(kmp算法)

【题目描述】
原题来自:POI 2006

串是有限个小写字符的序列,特别的,一个空序列也可以是一个串。一个串 P 是串 A 的前缀,当且仅当存在串 B,使得 A=PB。如果P≠A并且 P 不是一个空串,那么我们说 P 是 A 的一个 proper 前缀。

定义 Q 是 A 的周期,当且仅当 Q 是 A 的一个 proper 前缀并且 A 是 QQ 的前缀(不一定要是 proper 前缀)。比如串 abab 和 ababab 都是串 abababa 的周期。串 A 的最大周期就是它最长的一个周期或者是一个空串(当 A 没有周期的时候),比如说,ababab 的最大周期是 abab。串 abc 的最大周期是空串。

给出一个串,求出它所有前缀的最大周期长度之和。

【输入】
第一行一个整数 k,表示串的长度。

接下来一行表示给出的串。

【输出】
输出一个整数表示它所有前缀的最大周期长度之和。

【输入样例】
8
babababa
【输出样例】
24
思路:
看到这个题目描述就觉得这不是什么人话。。。看了两遍才懂它说的啥。其实就是:给你一个字符串t,找到它所有前缀字串的最长周期的长度的和。
周期是这样定义的:对于一个字符串A,找到它的一个前缀子串s,如果ss的前缀是A,那么s就是A的一个周期,如果A不是ss的前缀,那么s就不是A的周期。
明白题意之后就开始想样例,babababa,它的最长周期是什么,很明显是bababa。
接下来列举样例的每个前缀字串的最长周期:
b 0
ba 0
bab ba
baba ba
babab baba
bababa baba
bababab bababa
babababa bababa
可以注意到我们只要求出它的最短相同前后缀的长度就好了。比如bab的最短相同前后缀分别是b 和b。然后再用这个子串的长度减去这个最短相同前后缀的长度就可以了。
我们知道kmp算法中的next数组表示的意义是最长相同前后缀的长度。而这个题目中我们要求最短相同前后缀的长度,我们利用next数组,每次向前跳,当next[now]==0时停止,这里相当于到了最短相同前后缀的位置了。然后再用当前串长度i减去now就是最长周期了。(如果没有明白的话就手动模拟一下吧)
考虑到每次求最短相同前后缀的长度的过程存在重复计算的过程,是会超时的,所以我们需要对求解路径进行一下压缩(类似于并查集里的那个路径压缩)每次找到最短相同前后缀时执行一次next[i]=now就行了
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e6+10;
char a[N];
int p[N],n;
ll ans;
void pre()//预处理
{
    p[1]=0;
    int j=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;
    }
}
void get_ans()
{
    int now;
    for(int i=1;i<=n;i++)
    {
        now=i;
        while(p[now]!=0) now=p[now];
        if(p[i]!=0) p[i]=now;
        ans+=i-now;
    }
}
int main()
{
    scanf("%d",&n);
    scanf("%s",a+1);
    pre();
    get_ans();
    printf("%lld\n",ans);
    return 0;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值