馬拉車演算法 回文樹(回文自動機)

2021-09-26 06:43:20 字數 3565 閱讀 8356

下標 i :0 是$ , 原字串插入#字元變為 奇數長度,結尾位置新增@ 維持奇數字元個數

arr字串:經過處理的字串 , eg -> fabbac  「$ # f # a # b # b # a # c # @」  

輔助陣列p:p[i] 表示 arr字串 在 i 位置的最長回文半徑

兩個關係:

最長回文串(是原串"fabbac"的最長回文串長度) =  p[i] - 1;

以 i 為中心的 回文串( arr串 ) 起始位置(索引) = ( i - p[i] ) / 2;

知道這些,再看**就能秒懂了。

板子:

#include #include #include #include #include #include #include #include #include #include #include #include #define clear( x , y ) memset( x , y , sizeof(x) );

#define qcin() std::ios::sync_with_stdio(false);

using namespace std;

typedef long long ll;

const int maxn = 1e6 + 7;

const int inf = 1e9 + 7;

int n , m;

char s[maxn] , t[maxn];

int manacher()

// 第一步:預處理,將原字串轉換為新字串

int n = -1;

t[++n] = '$';

for (int i = 0 ; i < lens ; i++)

t[++n] = '#' , t[++n] = '@';

++n;

// 第二步:計算陣列p、起始索引、最長回文半徑

int p[n];

int id = 0, mx = 0;

int maxlength = -1;

int index = 0;

for (int j=1; jj ? min(p[2*id-j], mx-j) : 1;

// 向左右兩邊延伸,擴充套件右邊界

while (t[j+p[j]] == t[j-p[j]])

// 如果回文子串的右邊界超過了mx,則需要更新mx和id的值

if (mx < p[j] + j)

// 如果回文子串的長度大於maxlength,則更新maxlength和index的值

if (maxlength < p[j] - 1)

}return maxlength;

}int main()

套用ac自動機思想,建立兩顆樹

0樹 和 1樹 , 前者表示偶數回文串,後者表示奇數回文串

通過fail指標操作可以在兩棵樹中 來回跳躍

具體內容 就看**解釋,可以很好地理解

主要是要知道

還有一些點需要了解

我們計算給出的s串的 所有回文子串(包括重複的)的數目,有兩種方法

第一種是用count函式,但是計算的時候0樹 和1樹 的cnt被重複計算了,所以只算乙個就行。

void count() 

}

在for(1 ~ lens)的過程中 把每次的 num[last] 加到乙個sum中即可。思考一下,這個方法不僅是計算所有回文子串數目的方法,也是計算 已插入字符集(可以是1 ~ i 或 n ~ i) 的回文子串數目——包括重複部分(再強調一下)。

//sum[lens] 就是全部回文子串的數目

sum[0] = 0;

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

//_________________________________

//sum[1]也是全部回文子串的數目

sum[lens+1] = 0;

for(int i = lens ; i >= 1 ; --i)

當這個模板處理字串過長時可能會mle,這時候就需要一些處理,或者直接考慮放棄此演算法,改用manacher了,因為我們改用鍊錶模擬時,如果要處理的字串中字元範圍是100,很可能會tle,當然只有大小寫字母是能滿足的。

用下面第乙個模板1 在2e6 * 26時就會mle , 改用模板2 可過,當然速度稍慢一些,畢竟常數大了點。

const int maxn = 5e5 + 7;

const int inf = 1e9 + 7;

const int over = 26;

int n , m;

struct plt

void init()

int get_fail(int x)

void add(int c)

last = nxt[cur][c];

cnt[last]++; }

void count()

} void buildtree()

} void solve()

};

#include #include #include #include #include #include #include #include #include #include #include #include #define clear( x , y ) memset( x , y , sizeof(x) );

#define qcin() std::ios::sync_with_stdio(false);

using namespace std;

typedef long long ll;

const int maxn = 2e6 + 7;

const int inf = 1e9 + 7;

const int over = 26;

const ll mod = 51123987;

int n , m;

struct link //next的鄰接表

void clear(int x)

int get(int x,int y)

return 0;

}void insert(int x,int y,int z)

};struct plt

void init()

void input()

int get_fail(int x)

void add(int x)

cnt[last]++;

} void buildtree()

} void count()

} void solve()

};int main()

洛谷 4555

洛谷1659

(下面的 密碼:rushb)

hysbz - 3676

ural - 1960

uvalive - 7041

codeforces - 17e

hdu - 3948

回文樹(回文自動機) 筆記

回文樹詳解1 what is palindromic auto machine?回文自動機,又叫回文樹,是由俄羅斯人 mikhailrubinchik於2014年夏發明的 這是一種比較新的資料結構,在原文中已有詳細介紹與 實現。回文樹其實不是嚴格的樹形結構,因為它有是兩棵樹,分別是偶數長度的回文樹和...

最長回文 馬拉車演算法

總時間限制 10000ms 單個測試點時間限制 1000ms 記憶體限制 5120000kb描述 給出乙個只由小寫英文本元a,b,c.y,z組成的字串s,求s中最長回文串的長度.回文就是正反讀都是一樣的字串,如aba,abba等 輸入乙個檔案一組資料 每組輸入為一行小寫英文本元a,b,c.y,z組成...

回文自動機

回文自動機,又叫回文樹,是由俄羅斯人 mikhailrubinchik於2014年夏發明的 這是一種比較新的資料結構,在原文中已有詳細介紹與 實現。回文樹其實不是嚴格的樹形結構,因為它有是兩棵樹,分別是偶數長度的回文樹和奇數長度的回文樹,樹中每個節點代表乙個回文串。為了方便,第一棵樹的根是乙個長度為...