hdu-1358 Period

Period
题目链接
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11292 Accepted Submission(s): 5282

Problem Description
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 <= i <= 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 AK , 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 <= N <= 1 000 000) – 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

Recommend
JGShining | We have carefully selected several similar problems for you: 1711 1686 3746 3068 2203

题意
给出若干组 n 和长度为 n 的字符串,对于每组先输出“Test case #x”其中整数x为组号。
(对于每组)接下来输出字符串的任意前缀长度和 k ,要求这个长度的前缀必须可以由 k 个相同字符串组成其中 k>1 且为能取到的最大值。
提醒一下格式的问题,每组后面都无缘无故输出一个’\n’,还有就是用翻译的同学们要小心 ‘#’ 可能会被翻译成中文的 #,这里看不出区别,但是测评的时候是不一样的。

题解
定义字符串的下表从 1 开始标。

由于题目要求 k 要尽可能大,那么这个循环节就要尽可能小。例如某个前缀为 abababab 的字符串,对于这一个前缀应输出 8 4。
若某前缀是由若干循环节组成的,那么从第二个循环节开始,p数组的值开始递增,如图。
这里写图片描述
这是因为每个循环节肯定都是相同的。
所以除了第 1 个循环节,其它循环节中节点的 p[i] 都在上一个循环节里,而且是对应的。
因此我们可以求出循环节长度 = i - p[i]。

求出循环节长度,那么我们只需判断是否在某段循环节的结尾或是否是第一段循环节就好了。
(i %(i - p[i])==0&& i /(i - p[i])>1)

然而非循环节是否会满足呢?

对于循环节个数为 2 的前缀(循环节长度为 len),2*p[j] = j。对于比这玩意儿长度大 len 的前缀记作 S,若 S 的循环节也是 len,那么它肯定也是一个符合条件的。如果不为 len,那么唯一的可能就是中间突然不匹配了,得到一个初值,从新开始累积了,那么此时的 len 是很大的,所以不可能满足条件。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
int n,p[maxn],ans,tot;
char s[maxn];
bool F(int n)
{
    if (!n) return 0;
    printf("Test case #%d\n",++tot);
    memset(s,0,sizeof s);scanf("%s",s);
    int j=p[0]=-1,ans=-1,len;
    for (int i=1;i<n;i++)
    {
        while (j>=0&&s[i]!=s[j+1]) j=p[j];
        p[i]=j+=s[i]==s[j+1];
        if (p[i]<0) continue;
        len=i-p[i];ans=i+1;
        if (ans%len==0&&ans/len>1) printf("%d %d\n",ans,ans/len);
    }
    putchar('\n');
    return 1;
}
int main()
{
    do
    scanf("%d",&n);
    while(F(n));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/80632734