zoukankan      html  css  js  c++  java
  • [POI2006][luogu3435] OKR-Periods of Words [kmp+next数组]

    题面

    传送门

    思路

    先把题面转成人话:

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

    利用$next$的性质:前缀$i$的长度为$next[i]$的前缀和后缀是相等的

    这说明:如果有i一个公共前后缀长度为j,那么这个前缀i就有一个周期为i-j

    见下图

    显然图中蓝色线段是黑色线段的一个周期

    那么接下来的问题就容易了:

    先求出$next$数组

    对于每个前缀$i$,令$j=i$,然后在$j>0$的情况下令$j=next[j]$,最小的$j$就是答案,此时$ans+=i-j$

    一个优化:求出$j$以后,令$j=fail[i]$,这样能加快递归速度(相当于记忆化了)

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    char a[1000010];int n,fail[1000010];
    int main(){
        scanf("%d",&n);scanf("%s",a);int i,j;ll cnt=0;
        fail[0]=fail[1]=0;j=0;
        for(i=1;i<n;i++){//求解next
            while(j&&(a[i]!=a[j])) j=fail[j];
            j+=(a[i]==a[j]);fail[i+1]=j;
        }
        for(i=1;i<=n;i++){
            j=i;
            while(fail[j]) j=fail[j];
            if(fail[i]!=0) fail[i]=j;//记忆化
            cnt+=i-j;
        }
        printf("%lld",cnt);
    }
    
  • 相关阅读:
    stm32 单片机
    #pragma hdrstop
    #pragma预处理命令
    用define 宏定义注释符号
    ANSI 标准C 还定义了如下几个宏
    国际C 语言乱码大赛(IOCCC )
    深入浅出C语言中的柔性数组
    有符号数与无符号数之间运算问题
    c 语言 register 关键字
    Windows堆思维导图--Windows pro sp3
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8900630.html
Copyright © 2011-2022 走看看