SP263 PERIOD - Period
题目描述
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 A K ^{K} K , that is A concatenated K times, for some string A. Of course, we also want to know the period K.
输入输出格式
输入格式:
The first line of the input file will contains only the number T (1 <= T <= 10) of the 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.
输出格式:
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.
输入输出样例
2
3
aaa
12
aabaabaabaab
Test case #1
2 2
3 3
Test case #2
2 2
6 2
9 3
12 4
Solution:
题意就是求一个字符串的所有循环前缀的最大周期数(周期个数不能为1)。
这种字符串的周期问题,下意识想到去求所有前缀的最长公共前后缀(next数组),考虑到next的性质:$S|0~next[i]|=S|i-next[i]+1~i|$,当字符串$S|0~i|$存在循环周期时,必定存在$(i-next[i])|i$(反之亦然),即错位部分$S|next[i]~i|$一定是一个周期且是最小周期(因为是最长公共前后缀),那么周期数最多就是$\frac{i}{i-next[i]}$,由于题目中周期不能为本身,所以$next[i]$必须大于$0$才去判断。
代码:
#include<bits/stdc++.h> #define il inline #define ll long long #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--) using namespace std; int t,n,next[1000005]; char s[1000005]; int main(){ scanf("%d",&t); For(k,1,t){ scanf("%d%s",&n,s); next[0]=next[1]=0; For(i,1,n-1){ int p=next[i]; while(p&&s[i]!=s[p]) p=next[p]; next[i+1]=(s[i]==s[p]?p+1:0); } printf("Test case #%d\n",k); For(i,2,n) if(next[i]&&i%(i-next[i])==0) printf("%d %d\n",i,i/(i-next[i])); printf("\n"); } return 0; }