日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Manacher 例题讲解

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Manacher 例题讲解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • HDU 4513 吉哥系列故事——完美隊形II
      • 題意:
      • 題解:
      • 代碼:
    • HDU 3613 Best Reward
      • 題意:
      • 題解:
      • 代碼:
    • HDU 3068 最長回文
      • 題意:
      • 題解:
      • 代碼:
    • HDU 5371 Hotaru's problem
      • 題意:
      • 題解:
      • 代碼:
    • ABB (2020牛客國慶集訓派對day1)
      • 題意:
      • 題解:
      • 代碼:

HDU 4513 吉哥系列故事——完美隊形II

題意:

求一個最長的完美隊形,滿足左右對稱,從左到中間身高需保證不下降

題解:

在manacher模板的基礎上增加改動,

while(newStr[i-p[i]]==newStr[i+p[i]] && newStr[i-p[i]]<=newStr[i-p[i]+2] )

多添加一個newStr[i-p[i]]<=newStr[i-p[i]+2]條件,使得所求的回文串滿足要求

代碼:

#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #define PI acos(-1.0) #define E 1e-9 #define INF 0x3f3f3f3f #define LL long long const int MOD=10007; const int N=200000+5; const int dx[]= {-1,1,0,0}; const int dy[]= {0,0,-1,1}; using namespace std; int str[N]; int newStr[N*2]; int p[N*2]; int n; int init(){newStr[0]=-1;newStr[1]=0;int j=2;int len=n;for (int i=0;i<len;i++){newStr[j++]=str[i];newStr[j++]=0;}return j; }int manacher(){int len=init();int res=-1;int id;int mx=0;for(int i=1;i<len;i++){int j=2*id-i;if(i<mx)p[i]=min(p[j], mx-i);elsep[i]=1;while(newStr[i-p[i]]==newStr[i+p[i]] && newStr[i-p[i]]<=newStr[i-p[i]+2] )p[i]++;if(mx<i+p[i]){id=i;mx=i+p[i];}res=max(res,p[i]-1);}return res; }int main(){int t;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=0;i<n;++i)scanf("%d",&str[i]);printf("%d\n",manacher());}return 0; }

HDU 3613 Best Reward

題意:

一個由26個字母組成的項鏈,中間切開分成兩部分
兩部分必須是回文串,否則價值為0,26個字母的價值會給出
問兩個部分的價值和是多少

題解:

先求出項鏈價值的前綴和
跑一遍manacher
我們要將回文串分為兩部分,然后分別枚舉兩部分的中心,判斷左右兩部分是否為回文串,并記錄各自的價值,最后更新最大價值

代碼:

#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> using namespace std;const int mn = 500010;char ch[mn]; int val[30], VAL[mn];char temp[2 * mn]; int tp[2 * mn]; void manacher(char ch[]) {int len = strlen(ch);temp[0] = '@';for (int i = 1; i <= 2 * len; i += 2){temp[i] = '#';temp[i + 1] = ch[i / 2];}temp[2 * len + 1] = '#';temp[2 * len + 2] = '$';temp[2 * len + 3] = '\0';int tlen = 2 * len + 1;int mx = 0, id = 0;for (int i = 1; i <= tlen; i++){if (mx >= i)tp[i] = min(tp[2 * id - i], mx - i + 1);elsetp[i] = 1;while (temp[i - tp[i]] == temp[i + tp[i]])tp[i]++;if (mx < i + tp[i] - 1){mx = i + tp[i] - 1;id = i;}} }int main() {int T;scanf("%d", &T);while (T--){for (int i = 0; i < 26; i++){int t;scanf("%d", &t);val[i] = t;}scanf("%s", ch);int len = strlen(ch);VAL[0] = val[ch[0]- 'a'];for (int i = 1; i < len; i++)VAL[i] = VAL[i - 1] + val[ch[i] - 'a'];manacher(ch);int ans = -0x3f3f3f3f;int tlen = 2 * len + 1;for (int i = 3; i < tlen; i++){ /// 枚舉切割點if (temp[i] == '#'){int l = 0, r = 0;if (tp[(i + 1) / 2] == (i + 1) / 2) // 左側回文l = VAL[i / 2 - 1];if (tp[(i + tlen) / 2] == (tlen - i) / 2 + 1) // 右側回文r = VAL[len - 1] - VAL[i / 2 - 1];ans = max(ans, l + r);}}printf("%d\n", ans);} }

HDU 3068 最長回文

題意:

求回文串的長度

題解:

裸題套模板

代碼:

#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> using namespace std; const int N = 22000010; char s[N]; char str[N]; int p[N]; int init() {int len = strlen(s);str[0] = '@', str[1] = '#';int j = 2;for (int i = 0; i < len; ++i) str[j++] = s[i], str[j++] = '#';str[j] = '\0';return j; } int manacher() {int ans = -1, len = init(), mx = 0, id = 0;for (int i = 1; i < len; ++i) {if (i < mx) p[i] = min(p[id * 2 - i], mx - i);else p[i] = 1;while (str[i + p[i]] == str[i - p[i]]) p[i]++;if (p[i] + i > mx) mx = p[i] + i, id = i;ans = max(ans, p[i] - 1);}return ans; }int main() {while(cin>>s){cout << manacher()<<endl;}// cin >> s;return 0; } //abahabuk

HDU 5371 Hotaru’s problem

題意:

找一個序列,滿足第一部分和第三部分一樣,第一部分和第二部分是對稱的。
例如2,3,4,4,3,2,2,3,4
求最長長度是多少?

題解:

滿足題目要求的序列,就是兩個相鄰的回文串,共享中間的一部分
我們可以認為,
左邊的回文串長度的一半>=共享部分的長度
右邊的回文串長度的一半>=共享部分的長度
不可能小于,不然中間共享部分就不成立了
所以我們根據左邊的回文串長度的一半,來判斷右邊回文串是否符合要求,如果如何就記錄最大值
如果左邊回文串的中心是i
那么右邊回文串的中心就是i+p[i]-1

while( len>an && p[i+len]-1-len<0 )

代碼:

#include<bits/stdc++.h> using namespace std; const int maxn=100000*3; int s[maxn],str[maxn],p[maxn]; int len1,len2; void init() {str[0]=-2;str[1]=0;for(int i=0;i<len1;i++){str[i*2+2]=s[i];str[i*2+3]=0;}len2=len1*2+2;str[len2]=-3; } void manacher() {init();int id=0,mx=0;for(int i=1;i<len2;i++){if(mx>i)p[i]=min(p[2*id-i],mx-i);elsep[i]=1;for(;str[i+p[i]]==str[i-p[i]];p[i]++);if(p[i]+i>mx){mx=p[i]+i;id=i;}} } int main() {int t;scanf("%d",&t);int cas=0;while(t--){cas++;scanf("%d",&len1);for(int i=0;i<len1;i++){scanf("%d",&s[i]);}manacher();int sum=0;for(int i=3;i<len2;i+=2){if(p[i]-1>sum){int len=p[i]-1;while( len>sum && p[i+len]-1<len)len--;sum=max(sum,len);}}printf("Case #%d: %d\n",cas,sum/2*3);} }

ABB (2020??蛧鴳c集訓派對day1)

題意:

長度為n的字符串,問最少添加多少字符可以使其構成回文字符串

題解:

最長回文字符串我的第一反應是manacher馬拉車算法,那我們直接馬拉車找到已有最長回文串,然后總長度減去不就是答案嗎?非也 ~ ~ 。注意是讓我們構造最長回文字符串,我們會發現,如果我們用馬拉車找到的最長回文串的最右端不是字符串最右端,那此情況就相當于作廢
比如:
murderforajarofz
我們可以找到最長回文串forajarof,但是最后一位z并不在里面,那你無論怎么構造也用不到forajarof這個回文串,也就是我們要找最長的帶最后一個字符的回文字符串
我們直接在manacher的基礎上改就可以,原本式子中的ans,我們每查找完一次清零,也就是如果找到的回文串不是帶尾的不要,如果帶尾保留最大值
詳細看代碼

代碼:

#include <bits/stdc++.h> using namespace std; const int maxn = 9*1e5+4; char s[maxn]; char str[maxn]; int p[maxn];//表示以i為中心的最長回文子串長度,int init() {int len = strlen(s);str[0] = '@', str[1] = '#';int j = 2;for (int i = 0; i < len; ++i) str[j++] = s[i], str[j++] = '#';str[j] = '\0'; // cout<<j<<endl;return j; } int manacher() {int len = init(),sum=-1; int mx = 0;//同時記錄一個當前延伸最遠的回文子串 int id = 0;//對稱中心 int ans = -1;for (int i = 1; i < len; ++i) {if (i < mx) p[i] = min(p[id * 2 - i], mx - i);else p[i] = 1;while (str[i + p[i]] == str[i - p[i]]) p[i]++;//if(i+p[i]==len-1) if (p[i] + i > mx) mx = p[i] + i, id = i;// cout<<"id="<<id<<endl;ans = max(ans, p[i] - 1);if(mx==len)sum=max(sum,ans);//cout<<"ans="<<ans<<endl;//cout<<"mx="<<mx<<endl;//cout<<"sum="<<sum<<endl;ans=0;}return sum; } int main() {int t;cin>>t;for(int i=0;i<t;i++)cin>>s[i];if(manacher()==0)cout<<t-1<<endl;else cout <<t-manacher()<<endl;return 0; }

總結

以上是生活随笔為你收集整理的Manacher 例题讲解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。