OKR-Periods of Words

题目大意:

对于给定串的每个前缀i,求最长的,使这个字符串重复两边能覆盖原前缀i的前缀(就是前缀i的一个前缀),求所有的这些“前缀的前缀”的长度和。

解题思路:

KMP
先初始化所有next
利用 next的性质:前缀 i 的长度为 next[i] 的前缀和后缀是相等的
这说明:如果有i一个公共前后缀长度为j,那么这个前缀i就有一个周期为i-j
对于每个前缀 i ,令 j=i ,然后在 j>0 的情况下令 j=next[j],最小的 j 就是答案,此时 ans+=i-j
一个小优化:求出 j 以后,令 j=next[i]。

Accepted code:

没加优化在洛谷跑了116ms
加了洛谷的o2跑了80ms

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#define ll long long
using namespace std;
char a[1000001];int n,next[1000001];
inline void read(int &f)
{
    char c=getchar(); f=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)){f=(f<<3)+(f<<1)+c-48;c=getchar();}
    return;
}
void write(ll x)
{if(x>9)write(x/10);putchar(x%10+48);return;}
int main()
{
    read(n);
    int j=0;
    while(j!=n) a[j++]=getchar();
    j=0; ll cnt=0;
    next[0]=next[1]=0;
    for(int i=1;i<n;i++)
    {
        while(j&&(a[i]!=a[j])) j=next[j];
        j+=(a[i]==a[j]);
        next[i+1]=j;
    }
    for(int i=1;i<=n;i++)
    {
        j=i;
        while(next[j]) j=next[j];
        if(next[i]!=0) next[i]=j;
        cnt+=i-j;
    }
    write(cnt);
}

猜你喜欢

转载自blog.csdn.net/qq_39798042/article/details/81783681