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牛客国庆集训派对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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NOI.AC#2139-选择【斜率优化dp,树状数组】

正题 题目链接:http://noi.ac/problem/2139 题目大意 给出nnn个数字的序列aia_iai​。然后选出一个不降子序列最大化子序列的aia_iai​和减去没有任何一个数被选中的区间数量。 1≤n≤106,1≤ai≤1081\leq n\leq 10^6,1\leq a_i\leq 10^81≤n≤106,1≤ai​≤108 解题思路 嗯…

codeforces1485 E. Move and Swap(dp)

E. Move and Swap Heltion 由于红色硬币向下一层走的时候只能走儿子&#xff0c;而蓝色无限制&#xff08;对后续操作无影响&#xff09;&#xff0c;于是考虑下面表示 状态表示&#xff1a;fuf_ufu​表示当前是红色硬币&#xff0c;向下一层走后的最大价值。 状态转移&#…

一个技术管理者的苦逼【技术管理漫谈】

希望给你3-5分钟的碎片化学习&#xff0c;可能是坐地铁、等公交&#xff0c;积少成多&#xff0c;水滴石穿&#xff0c;谢谢关注。角色转变 从工程师转技术管理这两年&#xff0c;好比头马变成车夫&#xff0c;除了角色认知的转变&#xff0c;还要看方向&#xff0c;定计划。不…

KMP Trie 例题讲解

文章目录HDU 4763 Theme Section题意&#xff1a;题解&#xff1a;代码&#xff1a;POJ 3630 Phone List题意&#xff1a;题解&#xff1a;代码&#xff1a;HDU 3746 Cyclic Nacklace题意&#xff1a;题解&#xff1a;代码&#xff1a;HDU 2087 剪花布条题意&#xff1a;题解&a…

P4640-[BJWC2008]王之财宝【OGF,Lucas定理】

正题 题目链接:https://www.luogu.com.cn/problem/P4640 题目大意 nnn种物品&#xff0c;其中ttt种物品是有个数限制的&#xff0c;第iii种限制为bib_ibi​&#xff0c;求选出mmm个物品的方案数%p\% p%p的值 1≤n,m,bi≤109,0≤t≤15,p∈[1,105]∩Pri1\leq n,m,b_i\leq 10^9,0…

[机器翻译]参与 Microsoft 开放源代码软件项目的方式

下面是一个事实&#xff1a;Microsoft 托管在 GitHub&#xff0c;包括.NET 编译器平台&#xff0c;也称为"Roslyn"具有多达 4 万行代码等一些相当大的大约 2,000 开放源代码软件 (OSS) 存储库。很多开发人员的代码将更改提交到数以百万计的计算机运行的项目可能会令人…

codeforces1485 F. Copy or Prefix Sum(dp)

F. Copy or Prefix Sum Venice technique简要就是懒标记思想。 由于前缀和数组和原数组一一对应&#xff0c;这里我们选择求aia_iai​的前缀和数组的方案数&#xff08;下面aia_iai​表示原题数组的前缀和&#xff09; 不难得知原题目的两个条件即 biai−ai−1→aibiai−1b_ia…

【蓝桥杯】 2018年国赛 矩阵求和

题目 题目&#xff1a; 经过重重笔试面试的考验&#xff0c;小明成功进入 Macrohard 公司工作。 今天小明的任务是填满这么一张表&#xff1a; 表有 n 行 n 列&#xff0c;行和列的编号都从1算起。 其中第 i 行第 j 个元素的值是 gcd(i, j)的平方&#xff0c; gcd 表示最大公…

F - GCD or MIN(数论)

F - GCD or MIN 首先gcd⁡(x,y)≤min⁡(x,y)\gcd(x,y)\leq \min(x,y)gcd(x,y)≤min(x,y) 数组中任意2个数的gcd可能是一种方案&#xff0c;任意3个数的gcd可能是一种方案… 如果我们能够把原数组任意个数的gcd全部列出来&#xff0c;能够满足题意的数一定在这些数之中&#…

P4199-万径人踪灭【FFT】

正题 题目链接:https://www.luogu.com.cn/problem/P4199 题目大意 给出一个只包含a,ba,ba,b的字符串 求有多少个不连续的回文子序列&#xff08;字母回文&#xff0c;位置对称&#xff09; 1≤n≤1051\leq n\leq 10^51≤n≤105 解题思路 这个不连续一看就很nt&#xff0c;考…

被低估的.net(上) - 微软MonkeyFest 2018广州分享会活动回顾

前天, 2018年11月10日, 广州图书馆\微软云开发者社区\广东职业教育信息化研究会\珠三角技术沙龙在广州图书馆负一层1号报告厅搞了一场”微软最有价值专家(MVP)广州分享会 - MonkeyFest 2018广州分享会”. 这是在广州图书馆官方微信公众号上的活动报名链接: https://mp.weixin.q…

[蓝桥杯][2017年第八届真题]发现环

题目链接 题目描述 小明的实验室有N台电脑&#xff0c;编号1~N。原本这N台电脑之间有N-1条数据链接相连&#xff0c;恰好构成一个树形网络。在树形网络上&#xff0c;任意两台电脑之间有唯一的路径相连。 不过在最近一次维护网络时&#xff0c;管理员误操作使得某两台电脑之间增…

P7323-[WC2021]括号路径【并查集,启发式合并】

正题 题目链接:https://www.luogu.com.cn/problem/P7323 题目大意 给出nnn个点的一张有向图。每个边(u,v,w)(u,v,w)(u,v,w)表示u−>vu->vu−>v有一个类型www的左括号边&#xff0c;v−>uv->uv−>u有一个类型www的右括号边。 求图中有多少点对满足它们之间…

P3565 [POI2014]HOT-Hotels(树形dp+长链剖分)

P3565 [POI2014]HOT-Hotels 参考题解 题目大意&#xff1a; 给定一棵树&#xff0c;在树上选 3 个点&#xff0c;要求两两距离相等&#xff0c;求方案数。 三个点树上两两距离为d存在下面两种情况 某个点三个子树&#xff08;保证该点是LCA&#xff09;中分别由三个点距离它为…

C#的RSA加密解密签名,就为了支持PEM PKCS#8格式密钥对的导入导出

差点造了一整个轮子.Net Framework 4.5 里面的RSA功能&#xff0c;并未提供简单对PEM密钥格式的支持&#xff08;.Net Core有咩&#xff1f;&#xff09;&#xff0c;差点&#xff08;还远着&#xff09;造了一整个轮子&#xff0c;就为了支持PEM PKCS#8、PKCS#1格式密钥对的导…

P4494-[HAOI2018]反色游戏【圆方树】

正题 题目链接:https://www.luogu.com.cn/problem/P4494 题目大意 给出nnn个点mmm条边的一张无向图&#xff0c;节点有0/10/10/1&#xff0c;每条边可以选择是否取反两边的点。 开始求将所有节点变为000的方案&#xff0c;然后对于每个点询问删去这个点之后的方案 1≤T≤5,1…

福州首届.NET开源社区技术交流会圆满成功

活动总结2018年11月10日周六的下午&#xff0c;在福州蒲公英创新工场举办了福州首届.NET开源社区技术交流会&#xff0c;来自福建省各大科技公司的技术小伙伴齐聚一堂&#xff0c;为了就是能在现场学习到微软跨平台技术.NET Core、微服务以及Azure云服务。在交流会现场&#xf…

【模板】高精度

ACM模板 #include<string> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct bign {int d[200010], len;bign() { memset(d, 0, sizeof d); len 1; }bign(int num) { *this num; }big…

POJ3734-Blocks【EGF】

正题 题目链接:http://poj.org/problem?id3734 题目大意 用思种颜色给nnn个格子染色&#xff0c;要求前两种颜色出现偶数次&#xff0c;求方案。 1≤T≤100,1≤n≤1091\leq T\leq 100,1\leq n\leq 10^91≤T≤100,1≤n≤109 解题思路 反正是EGF\text{EGF}EGF的十分入门题了。…

[蓝桥杯][2017年第八届真题]对局匹配

题目描述 小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分&#xff0c;代表他的围棋水平。 小明发现网站的自动对局系统在匹配对手时&#xff0c;只会将积分差恰好是K的两名用户匹配在一起。如果两人分差小于或大于K&#xff0c;系统都不会将他们…