JSOI2016 扭動的回文串

2022-05-31 19:39:09 字數 1753 閱讀 1771

description

jyy有兩個長度均為n的字串a和b。

乙個「扭動字串s(i,j,k)由a中的第i個字元到第j個字元組成的子串

與b中的第j個字元到第k個字元組成的子串拼接而成。

比如,若a=』xyz』,b=』uvw』,則扭動字串s(1,2,3)=』xyvw』。

jyy定義乙個「扭動的回文串」為如下情況中的乙個:

1.a中的乙個回文串;

2.b中的乙個回文串;

3.或者某乙個回文的扭動字串s(i,j,k)

現在jyy希望找出最長的扭動回文串。

input

第一行包含乙個正整數n。

第二行包含乙個長度為n的由大寫字母組成的字串a。

第三行包含乙個長度為n的由大寫字母組成的字串b。

1≤n≤10^5

output

輸出的第一行乙個整數,表示最長的扭動回文串。

sample input

5abcde

baecb

sample output

5hint

最佳方案中的扭動回文串如下所示(不在回文串中的字元用.表示):

.bc..

..ecb

首先我們需要知道扭動的回文串的兩種情況

1、它為a串或b串的子串

2、它的對稱中心有一部分在a串或b串

對於第一種情況十分好寫,這裡就不再多說,主要是講講第二種情況

對於 第二種情況而言,我們首先列舉回文串中點 i,然後找到最大能擴張的最大範圍(i-p[i]i+p[i]),若回文串的中點在a串,則a串所能繼續取到的範圍是(1i-p[i]-1),而b串中所能取到的範圍是(i+p[i]~len),若中心點在b串類似。

那麼下一步我們該怎麼做?二分長度。二分乙個長度,然後判斷a的一部分和b串的一部分是否一樣

如何判斷?雜湊。記錄雜湊出來的值的字首和,b串記錄字尾和,判斷的時候做類似字首和的減法即可,記得雙雜湊

依然不懂?上**

#include#include#include#include#include#define inf 0x7f7f7f7f

using namespace std;

typedef long long ll;

typedef unsigned int ui;

typedef unsigned long long ull;

inline int read()

inline void print(int x)

const int n=1e5,limit=27,p1=100007,p2=233333;

char a[n*2+10],b[n*2+10];

int pa[n*2+10],pb[n*2+10];

int suma[2][n*2+10],sumb[2][n*2+10],g[2][n*2+10];

int len,ans;

void work(char *s,int *p)

return ans;

}int main()

for (int i=2;i>1,r>>=1;

ans=max(ans,pb[i]+solve(l,r+1)*2);

} printf("%d\n",ans);

return 0;

}

JSOI2016 扭動的回文串

可以發現最後的答案一定長成 a 串和 b 串的一對對稱的子串 長度可以為 0 然後中間夾著 a 串或者 b 串中的乙個回文串 長度可以為 0 對於每乙個中心點,對應的最大的答案中間所夾的那個回文串一定是以這個中心點為對稱中心的最長回文串 那麼就從以這個中心點為對稱中心的最長回文串的兩邊開始找那個 a...

JSOI2016 扭動的回文串

清新結論配上巨大碼量的雜湊解法 第一種情況和第二種情況很容易解決,可以直接求乙個正向雜湊值在求乙個反轉後的雜湊值,然後列舉回文中心,二分擴充套件了多少即可。思考扭動的回文串應該滿足那些特性,首先,一定是一段滿足情況 1 或情況 2 的子串 s 然後左邊新增了一些,右邊新增了一些,很明顯,無論 s 是...

JSOI 2016 扭動的字串

給出兩個長度為 n 的字串 a,b s i,j,k 表示把 a 中的 i,j 和 b 中的 j,k 拼接起來的字串 問所有回文的 s i,j,k 或者 a,b 中的回文子串的最長長度 列舉回文串的中心。可以發現,如果能在當前字串內擴充套件就盡量擴充套件,不能擴充套件了再嘗試和另乙個字串匹配。對於前者...