Period 【HDU - 1358】【KMP求週期】

學習KMP算法可以參閱這篇文章,不懂的可以在線回答

題目鏈接


題意:

我們想知道一串字符中的前綴中有多少最大週期數,例如“aaa”中,前兩個“aa”最小週期長度爲“a”,所以週期長度爲2,前三個“aaa”的最小週期也是“a”所以週期長度爲3;再如“aabaabaabaab”中前6個“aabaab”的最小週期長度爲“aab”,所以週期爲2......。


  這道題就是要理解KMP的運行過程才能好做些,我們瞭解到next[]數組的遍歷規律,恰好就是前綴的關係,譬如“aabaab”的前綴next[]數組的存儲是這樣的{0, 1, 0, 1, 2, 3},對於前兩個“aa”,它們的規律是第二個“a”恰是在第一個基礎上的,證明前面恰好一個與其相等且呈週期性,那麼再舉例到“aabaab”,我們看到第五個字符“a”,他的next[]值爲“2”,但是以它爲終止的話卻不能恰好構成一個完整的週期而我們剪去它的值就是殘餘數,是5(第5個)-next[5](前面的週期關係)=5-2=3,而5%3!=0,所以不構成周期,而第六個字符以類似規律可以。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>    
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN=1e6+5;
char a[maxN];
int N, nex[maxN];
void cal_nex()
{
    nex[0] = nex[1] = 0;
    int k = 0;
    for(int i=2; i<=N; i++)
    {
        while(k>0 && a[k+1]!=a[i])
        {
            k = nex[k];
        }
        if(a[k+1] == a[i]) k++;
        nex[i] = k;
    }
}
int main()
{
    int Cas=0;
    while(scanf("%d", &N) && N)
    {
        getchar();
        scanf("%s", a+1);
        cal_nex();
        printf("Test case #%d\n", ++Cas);
        for(int i=2; i<=N; i++)
        {
            int tmp = i - nex[i];
            if(i>tmp && i%tmp==0) printf("%d %d\n", i, i/tmp);
        }
        printf("\n");
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章