题目链接
分析
可以递归的想,如果有回文,那么肯定是做2操作划算一些,记 manacher 算法中以 为中心的回文串半径,注意这里只能是偶数长度的回文串。具体来说 str[l,r] 的操作代价为
注意由于是回文串,递归计算最多有 次,因此暴力剪枝丫就算就好,
code
#include <bits/stdc++.h>
using namespace std;
#define MAXN (200100)
#define MOD 1000000007
#define ms(x,v) memset((x),(v),sizeof((x)))
#define INF 0x3f3f3f3f
#define pb push_back
#define fi first
#define se second
#define mp make_pair
typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int,int > Pair;
/***** field ****/
char str[MAXN],pp[MAXN*2];
int R[MAXN*2]; // 回文串半径
int n,len;
int ans =0;
/********function *********/
void manacher(){
// preprocess
n = strlen(str+1);
len=1;
char pad = '#';
pp[0] = '$';
for(int i=1 ; i <= n ; ++i){
pp[len++] = pad;
pp[len++] = str[i];
}
pp[len++] = pad;
ms(R,0);
int mr=0,zx =0;//mr 刚好越过最右回文的点
for(int i=1 ; i<len ; ++i){
R[i] = mr > i? min(R[2*zx -i],mr -i) : 1;
while (pp[i+R[i]]==pp[i-R[i]])++R[i];
if(i+R[i]> mr){
mr = i+R[i];
zx = i;
}
}
}
int solve(int l,int r){
if(r<l)return 0;
if(r-l <=1)return r-l+1;
int sz = r-l+1;
int ret = sz;
for(int i=(l<<1)+1 ; i <=(r<<1) ; i+=2){
int rad = min(R[i],min(i-(l<<1)+2,2*r+2 - i)) -1;
if(sz - rad+1 >=ret)continue;
int ll = (i+1)>>1;
int rr = (i+rad)>>1;
int remain = sz - rad+1 + solve(ll,rr);
ret = min(ret,remain);
}
return ret;
}
int main(int argc, char const *argv[]) {
ios_base::sync_with_stdio(0);
cin.tie(0);
int T;
cin>>T;
while (T--) {
cin >> (str+1);
manacher();
// for(int i=1 ; i<=len ; ++i)std::cout << R[i] << ' ';std::cout << '\n';
std::cout << solve(1,n) << '\n';
}
return 0;
}