1. 程式人生 > >【POJ2406】Power Strings 中文題意&題解&程式碼(C++)

【POJ2406】Power Strings 中文題意&題解&程式碼(C++)

Power Strings

Time Limit: 3000MS Memory Limit: 65536K

Description
Given two strings a and b we define a*b to be their concatenation. For example, if a = “abc” and b = “def” then a*b = “abcdef”. If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = “” (the empty string) and a^(n+1) = a*(a^n).

Input
Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output
For each s you should print the largest n such that s = a^n for some string a.

Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3

Hint
This problem has huge input, use scanf instead of cin to avoid time limit exceed.

中文題意:題目輸入若干個字串,對於每個字串求最短的迴圈節,並輸出迴圈節的長度,若沒有迴圈節則輸出1,注意abcdab的迴圈節不為abcd,它沒有迴圈節,因此若輸入abcdab則輸出1,輸入一個 . 表示輸入結束。

題解:
這道題十分巧妙的用到了kmp中nex陣列的性質,它表示
s [ 0 … nex[i] ] == s [ i-nex[i]+1 … i ]
假如一個字串 s 存在迴圈節時 t ,那麼如圖
這裡寫圖片描述


因為nex的定義是最長的字首等於字尾,所以如果存在迴圈節時,len-nex[len]就一定是最短的那個迴圈節的長度,當len%(len-nex[len])==0時,說明存在迴圈節,否則就不存在,證明如下:
這裡寫圖片描述
假如 nex[len] 位置 x 時
當 len%(len-nex[len])==0 時,那麼 len%(len-nex[len]-a.len-b.len)==0(因為a.len=b.len=len-nex[len]),所以中間重疊的部分也可以被分為長度為 len-nex[len] 的字串,此時a1==b2 b2==b3 a3==b4
又因為 a==b可以推出 a1==b1==a2==a3==a4==b2==b3==b4。
所以len-nex[len]為迴圈節的長度。
假若 len%(len-nex[len])!=0 ,由以上可以看出中間重疊的部分不能正好分成長度為 len-nex[len] ,因此也不可能出現迴圈節。

程式碼:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
int len,nex[1000005];
char s[1000005];
void getnex()
{
    int j=-1;
    for (int i=0;i<len;i++)
    {
        while(j!=-1 && s[j+1]!=s[i]) j=nex[j];
        if (s[j+1]==s[i] && i!=0) j++;
        nex[i]=j;
    }
}
int main()
{
    while(scanf("%s",s))
    {
        if (s[0]=='.')
        break;
        len=strlen(s);
        getnex();
        if (len%(len-nex[len-1]-1)==0&&len!=nex[len-1]+1)
        printf("%d\n",len/(len-nex[len-1]-1));
        else 
        printf("1\n");
    }
}