翻转一个区间使得字符串成为回文串
题目
子串翻转回文串 http://acm.zzuli.edu.cn/problem.php?id=2700
题目描述
给一个串 s=s1s2⋯sn,你可以选定其一个非空子串,然后将该子串翻转。具体来说,若选定的子串区间为 [l,r](1≤l≤r≤n),则翻转后该串变为 s1s2⋯sl−1srsr−1⋯slsr+1⋯sn。
请你回答仅通过一次上述操作后,s 是否能变成回文串。串 s 是回文串,当且仅当它从左至右读出与从右至左读出完全相同,即 s1s2⋯sn=snsn−1⋯s1
输入
注意:本题包含多组测试数据。
第一行包含一个整数 T(1≤T≤5×10^5),表示数据组数。
接下来的 T 行,每行包含一个仅由英文小写字母组成的字符串 s,含义见题目描述,且串长 ∣s∣ 满足1≤∣s∣≤5×10^5。
保证字符串总长 ∑∣s∣不超过 5×10^5。
输出
对于每组测试数据,输出一行一个字符串,若仅通过一次操作后 s 能变成回文串,则输出 Yes,否则输出 No,大小写不敏感。
样例输入
4
abba
bacad
abacbaa
aabadcdca
样例输出
Yes
No
Yes
Yes
提示
第一组数据中,abba 翻转带下划线的子串得到回文串 abba。
第二组数据中,无论如何翻转子串,都不能得到回文串。
第三组数据中, abacbaa翻转带下划线的子串得到回文串 aabcbaa。
第四组数据中, aabadcdca翻转带下划线的子串得到回文串 acdabadca。
思路
我们首先得到一个结论:
我们把s[1]和s[n]匹配。
s[2]和s[n-1]匹配。
...
s[pL]是第一个和s[pR]不相等的。
那么翻转的一个端点一定pL或者pR。那么我们枚举一下,再枚举另外一个端点。
这个时候复杂度为O(n),我们再考虑怎么处理翻转和判断回文。
我们维护一个反串。设原串为1,反串为2。那么1串翻转[L, R]和2串翻转[n-r+1, n-r+1+r-l]得到的串相等的话就说明翻转后
得到的是回文串。我们判断相等这里只能用哈希值。那怎么得到翻转的哈希值。这里又用到了反串的哈希。
我们把1串分成3部分。中间翻转[L, R]的部分的哈希值不就是反串的[n-r+1, n-r+1+r-l]的哈希值。
所以维护2个哈希就可以了。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=500005;
struct Hash_char{
const LL mod=998244353, base=131;
LL p[maxn], g[maxn];
void getp(){
p[0]=1;
for(int i=1; i<maxn; i++){
p[i]=p[i-1]*base%mod;
}
}
LL Hash(char s[]){
int len=strlen(s+1);
g[0]=0, g[1]=s[1];
for(int i=2; i<=len; i++){
g[i]=(g[i-1]*base+s[i])%mod;
}
return g[len];
}
LL getLR(int l, int r){//得到s[l]-s[r]的hash值
if(l>r) return 0;
LL ans=((g[r]-g[l-1]*p[r-l+1])%mod+mod)%mod;
return ans;
}
}T[2];
int n;
LL strfz(int pos, int l, int r){//pos:正反串,翻转区间l, r。
LL ans=T[pos].getLR(1, l-1)*T[pos].p[n-l+1]%T[pos].mod;
LL res=T[pos^1].getLR(n-r+1, n-r+1+r-l)*T[pos].p[n-r]%T[pos].mod;
ans=ans+res+T[pos].getLR(r+1, n);
return ans%T[pos].mod;
}
char s[maxn], s1[maxn];
int main(){
T[0].getp(); T[1].getp();
int t; scanf("%d", &t);
while(t--){
scanf("%s", s+1);
n=strlen(s+1);
for(int i=1; i<=n; i++){
s1[i]=s[n-i+1];
}
s1[n+1]=0;
T[0].Hash(s); T[1].Hash(s1);
int pl=1, pr=n;
while(s[pl]==s[pr]&&pl<=pr){
pl++, pr--;
}
int f=0;
for(int i=pl; i<=n; i++){
if(strfz(0, pl, i)==strfz(1, n-i+1, n-i+1+i-pl)){
f=1; break;
}
}
for(int i=pr; i>=1; i--){
if(strfz(0, i, pr)==strfz(1, n-pr+1, n-pr+1+pr-i)){
f=1; break;
}
}
if(f||pl>=pr) printf("Yes\n");
else printf("No\n");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了