manacher演算法學習心得
阿新 • • 發佈:2018-12-09
manacher演算法,演算法處理迴文字串。
通過初始化,在s串前加'$'在各個字元之間加'#'構成一個新的奇長度的串,對於這個串,進行預處理,構造p陣列,其中p[i]-1等於迴文串長度,處理方法見程式碼:
#include <iostream> #include <cstring> #include <algorithm> using namespace std; char s[1000]; char s_new[2000]; int p[2000]; int Init() { int len = strlen(s); s_new[0] = '$'; s_new[1] = '#'; int j = 2; for (int i = 0; i < len; i++) { s_new[j++] = s[i]; s_new[j++] = '#'; } s_new[j] = '\0'; // 別忘了哦 return j; // 返回 s_new 的長度 } int Manacher() { int len = Init(); // 取得新字串長度並完成向 s_new 的轉換 int max_len = -1; // 最長迴文長度 int id; int mx = 0; for (int i = 1; i < len; i++) { if (i < mx) p[i] = min(p[2 * id - i], mx - i); // 需搞清楚上面那張圖含義, mx 和 2*id-i 的含義 else p[i] = 1; while (s_new[i - p[i]] == s_new[i + p[i]]) // 不需邊界判斷,因為左有'$',右有'\0' p[i]++; // 我們每走一步 i,都要和 mx 比較,我們希望 mx 儘可能的遠,這樣才能更有機會執行 if (i < mx)這句程式碼,從而提高效率 if (mx < i + p[i]) { id = i; mx = i + p[i]; } max_len = max(max_len, p[i] - 1); } return max_len; }
例題:
程式碼:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define ll long long const int M=5e5+10; char s[M],s_new[2*M]; long long p[M*2]; long long trie[M*2]; void update(int x) { for(int i=x;i<=M;i+=i&(-i)) { trie[i]+=1; } } ll query(int x) { ll ans=0; for(int i=x;i;i-=i&(-i)) { ans+=trie[i]; } return ans; } int init() { s_new[0]='$'; s_new[1]='#'; int j=2; for(int i=0;s[i];i++) { s_new[j++]=s[i]; s_new[j++]='#'; } s_new[j]='\0'; return j; } void mancher() { int len=init(); int id; ll mx=0; for(int i=1;i<=len;i++) { if(i<mx) { p[i]=min(p[2*id-i],mx-i); } else p[i]=1; while(s_new[i-p[i]]==s_new[i+p[i]]) p[i]++; if(mx<i+p[i]) { id=i; mx=i+p[i]; } } } vector<int>e[M]; int main() { int t; scanf("%d",&t); while(t--){ ll ans=0; memset(trie,0,sizeof(trie)); scanf("%s",s); int len=strlen(s); mancher(); for(int i=1;i<=len;i++) e[i].clear(); for(int i=1;i<=len;i++) { int pos=(p[2*i]-1)/2; e[i-pos].push_back(i); } for(int i=1;i<=len;i++) { for(int j=0;j<e[i].size();j++) { update(e[i][j]); } ans+=query(i+(p[2*i]-1)/2)-query(i); } printf("%lld\n",ans); } return 0; }