UVA1328 Period

其他链接:luogu UVA1328 POJ1961

For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (\(2 \le i \le N\))we want to know the largest \(K > 1\) (if there is one) such that the prefix of \(S\) with length i can be written as \(A^K\), that is A concatenated K times, for some string A. Of course, we also want to know the period K.

Input

The input file consists of several test cases. Each test case consists of two lines. The first one contains \(N\) (\(2 \le N \le 1000000\)) the size of the string \(S\). The second line contains the string S. The input file ends with a line, having the number zero on it.

Output

For each test case, output ‘Test case #’ and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.

Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3
Test case #2
2 2
6 2
9 3
12 4

翻译

(louhc自己翻译的啦 luogu ID Sinner也是我)

题意描述

对于给定字符串S的每个前缀,我们想知道它是否为周期串。也就还是说,它是否为某一字符串重复连接而成(必须至少重复2次)(即循环节)。

输入

多组数据。每组数据,第一行一个数字表示长度,第二行一个字符串S。

输出

输出前缀长度与循环节数量。

说明

字符串长度不超过1000000,仅由小写字母组成。
对于每个前缀,只要输出长度最小的循环节


写在前面

Substr(i, j)表示s的子串s[i~j]

这里s的下标从1开始

i的上一个匹配:一个位置j,满足Substr(1, j) == Substr(i - j + 1,N)

下面黑线表示字符串,其中红框中包含的字符相等(这是自然,同一个字符串嘛)。

j还要满足

(注意啦 两条黑线表示同一个字符串,只是位置不同)

(其实这也算是KMP的复习吧。。。)

下面图中红框中都表示相同

算法

KMP。由于这不是KMP学习笔记,不仔细讲,请先学会KMP。

思路

这题也可算是“拍大腿”系列了吧?其实你看看下面代码,真的很简单,关键就是如何推出这个结论。

(我不用next,用了f做数组名,希望大家不要看不习惯,意思是一样的)

粉色部分也表示相同。这很明显,因为字符是一一对应的嘛(同一个字符串位置相同、长度相同的字符串当然一样)。

由于红框内完全相同,还可以——

继续对应!灰线表示在原字符串中是对应的。

还可以对应!

可能就会出现这样的情况!(当然可能最前面不够长度)

因此,只要f[i]>0,i前面肯定有循环节!(只不过不知道是否完整,bb|abb|abb|abb这样也看作是)而且循环节长度为i - f[i] + 1!。因此只要判断循环节长度能否将长度整除即可。具体请见代码(真的短)。

代码

#include<cstdio>
using namespace std;
#define MAXN 1000005

int N, T;
char s[MAXN];
int f[MAXN];

int main(){
    while( ~scanf( "%d", &N ) && N ){
        scanf( "%s", s + 1 ); T++;
        printf( "Test case #%d\n", T );
        int t(0); f[1] = 0;
        for ( int i = 2; i <= N; ++i ){
            while ( s[i] != s[t + 1] && t ) t = f[t];
            if ( s[i] == s[t + 1] ) t++;
            f[i] = t;
            if ( f[i] != 0 && i % ( i -  f[i] ) == 0 ) printf( "%d %d\n", i, i / ( i - f[i] ) );
        }
        putchar('\n');
    }
    return 0;
}