1. 程式人生 > >HDU3746 Cyclic Nacklace(KMP next陣列的應用)

HDU3746 Cyclic Nacklace(KMP next陣列的應用)

題意:給出一個字串,任務為將其擴充套件為其迴圈節的整數倍。輸出需要補上的珠子的數目。只能在最左邊和最右邊補。

樣例解釋:aaa,以a為迴圈節,該鏈子已經滿足要求。

                  abca,以abc為迴圈節,需要補上bc,組成abcabc。

       abcde,只能以自己為迴圈節,補上abcde,組成abcdeabcde。

解法:首先要理清楚思路。不管前面的next天花亂墜,012312101之類的,但是我們只關心最後一個的next,因為我們是從這裡開始補起來的。

           主要考查的是next的運用。假設字串長度為len,那麼如果next[len]處為0,則說明沒有迴圈節,直接輸出其長度len即可。如abcde。

                               否則,我們就把(len-next[len])作為迴圈節,然後在最後一個開始補,顯然補(len-next[len])- next[len] %(len-next[len])即可。如abababa,next為

                          -10012345,我們就把ab作為迴圈節,補上b即可,上面的運算就是(7-5)-5%(7-5) = 1。

                         再考慮一下特殊情況,比如aaa,next為-1012,此時算出來為(3-2)-2%(3-2)=1,問題出在哪裡呢?顯然此時的答案等於迴圈節長度,加上一個迴圈節長

                                                                                            度的字元是無用的,我們應該再對答案對迴圈節長度取一次模。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int nex[maxn];

void Find(char *p, int len) {
    nex[0] = -1;
    for(int i = 0, j; i < len; ++i) {
        j = nex[i];
        while(j != -1 && p[i] != p[j]) {
            j = nex[j];
        }
        nex[i + 1] = j + 1;
    }
}

char str[maxn];

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    int T;
    cin >> T;
    while(T--) {
        cin >> str;
        int len = strlen(str);
        Find(str, len);
        if(nex[len] == 0) {
            cout << len << endl;
        } else {
            int t_len = len - nex[len];
            cout << (t_len - nex[len] % t_len) % t_len << endl;
        }
    }
    return 0;
}