1 条题解
-
0
自动搬运
来自洛谷,原作者为

wyxrl
纯蒟蒻搬运于
2025-08-24 22:36:15,当前版本为作者最后更新于2025-08-20 08:14:03,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目大意
寻找头尾偶数回文子串,将其折叠,然后组成一个新的字符串,一直到没有一个偶数回文子串时输出剩下的长度。
思路分析
- 这道题需要找回文子串,我们首先考虑 Manacher 算法 来寻找。
- 题目中还有一种情况,例如:在序列 CCCCTTACCCC 中,分别有 CCCC 与 ,CCCC,等几个回文子串,折叠后因题目描述,组成的新的序列可能是 CCTTACC、CCCCTTA、TTACCCC,但是其实这些不影响最终答案,因为如果两个子串能折叠时,它们组成的大的回文子串一定能折叠。
代码思路
如果一个个去寻找回文子串,然后折叠组成新字符串的时间复杂度太高了,那么我们有更高效的解法。
我们可以从首尾依次寻找每个回文子串半径,更新左右端点。
但是可能会有多个重叠偶数回文子串怎办呢?
此时我们需要判断这个回文子串范围有没有超过左右端点。
注意左端点不能超过右端点,否则会重复删除。
代码实现
#include<bits/stdc++.h> using namespace std; const int MAXN=4e6+10; int sum[MAXN<<1],n,nt; char s[MAXN<<1],c[MAXN]; void init(){ int k=0; s[k++]='$'; //开头特殊符号 (判断边界) s[k++]='@'; for (int i=0;i<n;i++){ s[k++]=c[i]; s[k++]='@'; } s[k++]='^';//结尾特殊符号 (判断边界) nt=k; } void manacher(){ int mr=0,mid=0; for(int i=1;i<nt;i++){ if(i<mr) sum[i]=min(sum[2*mid-i],mr-i); else sum[i]=1; while(s[i+sum[i]]==s[i-sum[i]]) sum[i]++; if(i+sum[i]>mr){ mr=i+sum[i]; mid=i; } } } int main (){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>c; n=strlen(c); init(); manacher(); int l=1,r=nt-2; // 因为预处理字符串开头是'$',结尾是'^',所以有效部分从1到nt-2 for (int i=2;i<nt-1;i++){ // 处理左端点 if (s[i]=='@'&&i-sum[i]+1<= l){ l=i; } } for (int i=nt-2;i>l;i--){ //处理右端点 注意i>l防止r<l if (s[i]=='@'&&i+sum[i]-1>=r){ r=i; } } cout<<(r-l)/2; return 0; }
- 1
信息
- ID
- 7477
- 时间
- 5000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者