BZOJ1511 [POI2006]OKR-Periods of Words

题意

一个串是有限个小写字符的序列,特别的,一个空序列也可以是一个串. 一个串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的最大周期是空串. 给出一个串,求出它所有前缀的最大周期长度之和.

定义一个串的proper前缀为它的非空且不等于自身的前缀.定义一个串A的周期为Q,当且仅当Q为A的proper前缀,且A为QQ的前缀.求出一个串所有前缀的最大周期长度和.

分析

参照jklover的题解。

只需要沿着fail指针(失配边)往前跳,跳到第一个不为0的位置即可,可以路径压缩进行优化.

考虑一个串,如果它的构成形式为ABA,那么AB一定是它的周期。要AB最长,只需要A最短,也就是fail最小,调到第一个不为0的位置即可。关于那个路径压缩,可以归纳证明。

时间复杂度\(O(K)\)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>il T read(rg T&x)
{
    return x=read<T>();
}
typedef long long ll;

co int K=1e6+1;
char s[K];
int fail[K];

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int k;
    read(k);
    scanf("%s",s+1);
    for(int i=1;i<k;++i)
    {
        int j=fail[i];
        while(j&&s[j+1]!=s[i+1])
            j=fail[j];
        fail[i+1]=s[j+1]==s[i+1]?j+1:0;
    }
    ll ans=0;
    for(int i=1;i<=k;++i)
    {
        if(fail[fail[i]])
            fail[i]=fail[fail[i]];
        if(fail[i])
            ans+=i-fail[i];
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10323552.html