题目链接: http://codeforces.com/group/NVaJtLaLjS/contest/239052/problem/G
题面:
题目大意:给你一个字符串,每次翻转操作都是以一个字符为轴,给你一个前缀,问从哪个位置开始翻转可以得到一个前缀为给定串,输出位置序列。
解法:运用mancher算法算出每个位置的回文半径mp[i],在i>len的时候,若能成立我们有(mp[i]-1+i)/2 == len,在i<len的时候,我们有我们有通过判断翻转后的位置是否满足即可。
mancher算法学习链接:https://segmentfault.com/a/1190000008484167?utm_source=tag-newest
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e6+5;
char s[maxn],Ma[maxn];
int Mp[maxn],vis[maxn];
void Manacher(char s[], int len){
int l = 0;
Ma[l++] = '$';
Ma[l++] = '#';
for(int i=0;i<len;++i){
Ma[l++] = s[i];
Ma[l++] = '#';
}
Ma[l] = 0;
int mx = 0, id = 0;
for(int i=0;i<l;++i){
Mp[i] = mx>i? min(Mp[2*id-i], mx-i):1;
while(Ma[i+Mp[i]] == Ma[i-Mp[i]]) Mp[i]++;
if(i + Mp[i] > mx){
mx = i+Mp[i];
id = i;
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",s);
int len = strlen(s);
Manacher(s,len);
vis[len] = 1;
for(int i = 2*len-2;i >= 2; i -= 2){
vis[i/2] = 0;
int temp = (Mp[i]+i-1)/2;
if(temp == len)vis[i/2] = 1;
if(vis[temp]&&i <= len)vis[i/2] = 1;
}
for(int i = 1;i <= len; i++){
if(vis[i])printf("%d ",i);
}
putchar('\n');
}
return 0;
}