码迷,mamicode.com
首页 > 其他好文 > 详细

Power Strings

时间:2019-10-04 22:35:23      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:ati   为什么   style   连接   依次   解决   int   前缀   http   

https://loj.ac/problem/10035

题目描述

  给出一个字符串,求它的最小循环节。

思路

  之前讲过Hash的做法,不过这也是KMP的模板题。

  我们有结论:若n%(n - p [ n ])==0,最小循环节长度为n/(n - p [ n ]);否则就为它本身。

  我们对着证明考虑两部分,一是可以整除时为什么这是答案,而是为什么不能整除是最小循环节为它本身。

  ①如果n是(n - p [ n ])的倍数,我们可以把字符串分为若干段长(n - p [ n ])的字符串。首先我们把每段记为A、B、C、D(假设只有四段),所以D段表示的是字符串S[ p[ n ],n ]这一段,而由P数组的定义我们可知p[ n ]表示的n的最长公共前后缀,即S[ 1 ...p[ n ] ]前缀和S[ p[ n ] ...n ]后缀相同,所以我们有ABC=BCD(表示字符串依次连接),由于它们完全相等,所以A=B,B=C,C=D,所以可知A就是循环节,而很容易由反证法知道不存在更短的循环节,否则和p数组定义不符。其数目即为答案。

  ②我们需要解决为什么不整除时就最小循环节就是它本身。我们运用反证法,假设存在最小循环节长len(len!=n),那么S[ 1,len ]=S[ n-len,n ],那么len=n - p[n],而由假设知,n不被n - p [ n ]整除,但又由循环节定义知n被len整除,因此矛盾。

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
int pre[MAXN];
char s[MAXN];
int main() 
{
    while(~scanf(" %s",s+1))
    {
        int n=strlen(s+1);
        if(s[1]==.)break ;
        int j=0;pre[1]=0;
        for(int i=1;i<n;i++)
        {
            while(j>0&&s[i+1]!=s[j+1])j=pre[j];
            if(s[i+1]==s[j+1])j++;
            pre[i+1]=j;
        }
        if(n%(n-pre[n])==0)printf("%d\n",n/(n-pre[n]));
        else printf("1\n");
    }
    return 0;
}

 

Power Strings

标签:ati   为什么   style   连接   依次   解决   int   前缀   http   

原文地址:https://www.cnblogs.com/fangbozhen/p/11623004.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!