题意:
长度为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; }