「UVA1328」「POJ1961」 Period 解題報告
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\)
Input
The input file consists of several test cases. Each test case consists of two lines. The first one contains \(N\)
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;
}