传送门
区间dp
f[i][j][k]表示从第i个到第j个字符,k=1表示前面是否有M
1.枚举分割点(k=1),转移方程min(f[i][l]+f[l+1][j]+1)(中间放一个M)
2.枚举分割点,仅对前面的部分压缩,转移方程min(f[i][l][k]+j-l)
3.判断当前部分是否能被压缩。转移方程min(f[i][(i+j)/2][0]+1)
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
int f[55][55][2],v[55][55][2],l;
char s[55];
void min(int &x,int y){
if (y<x) x=y;
}
int same(int x,int y){
if ((x+y+1)%2) return 0;
int l=(y-x+1)/2;
for (int i=1;i<=l;i++)
if (s[x+i-1]!=s[x+i+l-1]) return 0;
return 1;
}
int dp(int l,int r,int p){
if (l==r) return 1;
if (v[l][r][p]) return f[l][r][p];
v[l][r][p]=1;
f[l][r][p]=r-l+1;
if (p) for (int i=l;i<r;i++) min(f[l][r][p],dp(l,i,1)+dp(i+1,r,1)+1);
for (int i=l;i<r;i++) min(f[l][r][p],dp(l,i,p)+r-i);
if (same(l,r)) min(f[l][r][p],dp(l,(l+r)/2,0)+1);
return f[l][r][p];
}
int main(){
scanf("%s",s+1);
l=strlen(s+1);
printf("%d",dp(1,l,1));
return 0;
}