2025-05-17

題意:找出所有前綴長度,使得這個長度的前綴==後綴


Sample Input
ababcababababcabab
aaaaa


Sample Output
2 4 9 18
1 2 3 4 5


看瞭HDU 1686 Oulipo


相信next值的意義就很清晰瞭


下面給出描述: (i>1)[下標從0開始]
next[i]的意義就是:前面長度為i的字串的【前綴和後綴的最大匹配長度】


那麼這題怎麼利用這個性質呢?


詳細分析一下:【就用上面的第一個例子說明吧】
求出next值:[非修正]
下標:      0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17
串:          a  b  a  b  c  a  b  a  b  a  b   a   b   c   a   b   a   b
next值:  -1  0  0  1  2  0  1  2  3  4  3   4   3   4   5   6   7   8   9


len2 = 18    next[len2] = 9
說明對於前面長度為18的字符串,【長度為9的前綴】和【長度為9的後綴】是匹配的, 即上圖的藍色跟紅色匹配
也就是整個串的最大前後綴匹配長度就是9瞭
所以接下來根本不需要考慮長度大於9的情況啦


好瞭!既然現在隻需考慮長度小於9的前後綴匹配情況,那麼
[問題就轉化成藍色串的前綴跟紅色串的後綴的匹配問題瞭!!!
又因為藍串==紅串
所以問題又轉化成
找藍串自己的前綴跟自己的後綴的最大匹配瞭!!!
那麼我們現在就要找next[9]的值瞭【next[9]的含義:藍串的最大前後綴匹配】


回憶第一步:我們找的是next[len2]=9【len2=18】
怎麼使得第二部目標變成9【求next[9]】呢?
其實next[len2]=9同時可以表示為:最大匹配前後綴的【前綴長度】
那麼next[9]的意義就是:
【主串】的最大匹配前後綴的【前綴】的【最大匹配前後綴】瞭!!
也就是上面藍串的前後綴最大匹配長度瞭!!


那麼算法描述就是:
第一步:求next[len2], 即next[18] = 9;
第二步:把9代進來,即求next[9] = 4;
第三步:把4代進來,即求next[4] = 2;
第四步:next[2] = 0; 也就是下標2之前的串已經沒有前後綴可以匹配瞭
所以答案就是: 2 4 9 18 【PS: 從小到大輸出,18是串長,必然符合題意】
局部實現代碼:


C++代碼 
j = next[len2]; 
while (j > 0) 
    ans[k++] = j, j = next[j];    //ans儲存答案 



C++代碼 
#include <iostream> 
#include <fstream> 
#include <algorithm> 
#include <string> 
#include <set> 
//#include <map> 
#include <queue> 
#include <utility> 
#include <stack> 
#include <list> 
#include <vector> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <ctime> 
#include <ctype.h> 
using namespace std; 
#define L2 400005 
 
int next[L2], len2, ans[L2]; 
char p[L2]; 
bool hash[L2]; 
 
void get_next()    //原始next函數 

    int k = -1, j = 0; 
    next[0] = -1; 
    while (j < len2) 
    { 
        if (k == -1 || p[j] == p[k]) 
        { 
            j++, k++; 
            next[j] = k; 
        } 
        else k = next[k]; 
    } 
    /*for (j = 0; j <= len2; j++)
        cout << next[j] << ;
    cout << endl;*/ 

int main() 

    int k, i, j; 
    while (scanf (“%s”, p) != EOF) 
    { 
        k = 0; 
        memset (hash, false, sizeof(hash)); 
        len2 = strlen (p); 
        get_next(); 
        j = next[len2]; 
        while (j > 0) 
            ans[k++] = j, j = next[j]; 
        for (i = k – 1; i >= 0; i–)    //倒過來輸出,就是從小到大瞭 
            printf (“%d “, ans[i]); 
        printf (“%d
“, len2); 
    } 
    return 0; 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *