題解 最長回文子串

2022-06-19 18:33:14 字數 1746 閱讀 4956

剛學完字尾陣列,用這道題來練練\(sa\)。

題目右**ural 1297

題意如題目,即給出乙個字串 \(s\) ,求 \(s\) 的最長回文子串。(\(|s|\leqslant1000\))

既然剛學了字尾陣列,自然使用字尾陣列做啦。

但如何將問題轉化為乙個 \(sa\) 問題呢\(?\)

先來觀察一下下面這個字串的回文子串吧。\(rt,\)

可以發現,回文子串 \(baaaab\),是由兩個部分組成(前半部分和後半部分)。前半部分是字串 \(aabaaaab\) 的字首的字尾,後半部分是原字串的字尾的字首,回文子串即為原字串的字首的字尾和原字串的字尾的字首兩部分組成(可能讀起來有點繞,需要認真理解)。

回文串有個重要的性質,即從字串中心將字串切開,後半部分剛好是反過來的前半部分(例如: \(abc\) 是反過來的 \(cba\) )。因此,若乙個子串是回文的,那麼其一定是由原字串某個字尾的字首和原字串的某個字首的字尾的公共部分組成的。

如果我們將字串調轉過來,在接到原字串的後面,中間隔乙個字典序最小的'板',這樣字首就會被調轉過來,『字首的字尾』就會變為『字尾的字首』。問題就轉化為了求某兩個字尾的最長公共字首,就可以用字尾陣列求解了。

(如果字尾陣列用\(dc3\)求解的話,時間複雜度會降為\(\theta(n)\))

首先,將字串調轉過來,連線到原字串的後面。然後在兩個字串交界處插入乙個字典序最小的字元,以隔開兩個字串。\(rt,\)

分兩種情況討論回文串1.長度為奇數的 2.長度為偶數的。

如果長度是奇數,就查詢字尾\(i\)和字尾\(n-i\)。看圖自行理解。(注意,\(n\)是整個字串的長度)

如果長度是偶數,就查詢字尾\(i\)和字尾\(n-i+1\)。請看圖自行理解。

至於查詢任意兩個字尾的最長字首,其實是查詢這兩個字尾的排名之間的\(height\)陣列的最小值。(原因在此不進行闡述),用\(rmq\)經過\(\theta(n)\)的預處理,即可\(\theta(1)\)的出答案。

**:

#includeusing namespace std;

const int maxn = 1005*2;

int rak[maxn], newrank[maxn], sa[maxn];

int sum[maxn], key2[maxn], height[maxn];

int rmq[20][maxn], log2[maxn];

int n, m;

char str[maxn];

bool cmp(int a, int b, int l)

void makesa()

for(int i=1; i<=n; i++) rak[i] = newrank[i];

if(rk == n) break; }}

void getheight()

}void getrmq()

for(int i=1; i<=n; i++)

int main()

for(int i=start, j = 1; j<=ans; j++, i++) printf("%c",str[i]);

return 0;

}

最長回文子串 最長回文子串行

1.最長回文子串行 可以不連續 include include include include using namespace std 遞迴方法,求解最長回文子串行 intlps char str,int i,int j intmain include include include using n...

題解 最長回文串

給定乙個字串 s 找到 s 中最長的回文子串,輸出其長度。你可以假設 s 的最大長度為 3000。第1行 1個字串 樣例輸入 babad 樣例輸出 對於乙個字串s l,r 他的最長回文字串有如下兩種情況 1.若s l s r 且 s l 1,r 1 為回文字串,則s l,r 會變為更長的乙個回文字串...

最長回文子串

描述 輸入乙個字串,求出其中最長的回文子串。子串的含義是 在原串連續出現的字串片段。回文的含義是 正著看和倒著看是相同的,如abba和abbebba。在判斷是要求忽略所有的標點和空格,且忽略大小寫,但輸出時按原樣輸出 首尾不要輸出多餘的字串 輸入字串長度大於等於1小於等於5000,且單獨佔一行 如果...