poj2406—KMP next陣列的性質求最小週期
阿新 • • 發佈:2018-12-24
題目大意:給出一個字串,求它最多有幾個連續子串構成
分析:KMP求最小週期——結論:如果一個字串有最小週期,那麼最小週期為n-next[n]
考慮整個串,根據next陣列的定義,前後匹配並且字首和相等的最長的字尾之間沒有交叉,那麼相等的部分的長度為next[n],並且從左往右相等。
如果希望中間的也是有s[1..next[n]]的幾個迴圈組成,那麼整個串就以next[n]為最小週期,但是如果這樣,next[n]就會變大,與現在的情況矛盾。
那麼n % (n-next[n])!=0,整個串為一個迴圈節,只有一個週期
①如果字首和字尾是有重疊的,如圖,那麼藍色和綠色相交的地方的第一個字母等於綠色的第一個字母……那麼中間至少有一個以s[1..n-next[n]]為迴圈節的字串。
證明:假設有這樣的例子ABAB……AB使得字首字尾有重疊並且中間重疊部分不是由那種迴圈節組成,比如ABABCAB ,ABABACAB,那麼將字尾往前平移的時候不能與字首重合。所以這種情況中間一定是迴圈節,並且和兩邊相等。
②如果單獨的藍色和綠色部分不相等而中間有重合,比如A.........C=>AA......CC顯然矛盾
這時n % (n-next[n])==0,並且迴圈節為n-next[n]
週期的個數為n / (n-next[n])
另外所有可能的週期長度為 n-next[n],n-next[next[n]],n-next[next[next[n]]]...
因為如果後面已經匹配了,相當於再在前next[x]個數中找一個相同的迴圈節,最小迴圈節*2 *3 *4之類的。。。如果再能被整除的話就是一個新的週期了
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; int next[1000010]; int n,t; char s[1000010]; void getnext() { int j=-1; next[0]=-1; for (int i=1;i<n;i++) { while (j>-1 && s[j+1]!=s[i]) j=next[j]; if (s[j+1]==s[i]) j++; next[i]=j; } } int main() { scanf("%s", s); while (s[0]!='.') { n=strlen(s); getnext(); t=next[n-1]+1; if (n % (n-t)==0) printf("%d\n", n / (n-t)); else printf("%d\n", 1); scanf("%s", s); } }