如果没有M的话,是一个正常的区间dp,我们可以列出来它的转移方程
① dp[l][r]=min( dp[l][r] , dp[l][j] + dp[j+1][r] );
如果当前区间(l,r)前半段和后半段相同,那就将它压缩一半然后加上一个R:
② dp[l][r]=min( dp[l][r] , dp[l][j] + 1 );

但是现在有一个M,因此就再加一种情况,定义dp[l][r][0/1],表示区间(l,r)有M和没有M时的最小值。
没有M时,我们要改一下①的式子,变成:
① dp[l][r][0]=min( dp[l][j][0] + r-j , dp[l][r][0]); (l<= j <=r)
因为对于后半段(j+1,r),因为没有M,要是压缩的话,会把(l,r)整个区间都压缩,所以后半段是不能压缩的,长度就是 r-j
前半段和后半段正好相等的时候:
② dp[l][r][0]=min( dp[l][r][0] , dp[l][(l+r)/2][0] + 1 );

有M的时候,枚举m的位置:
③ dp[l][r][1] = min( dp[l][r][1] , min( dp[l][j][1] , dp[l][j][0] ) + 1 + min( dp[j+1][r][1] , dp[j+1][r][0] ) );

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stack>
#include <queue>
#include <cmath>
#define ll long long
#define pi 3.1415927
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
int n,m;
int dp[1005][1005][2];
string s;
int judge(int l,int r)
{
    int mid=(l+r)/2;
    for(int i=l;i<=mid;++i)
        if(s[i]!=s[mid+1+i-l])
            return 0;
    return 1;
}
int main ()
{
    int T,i,t,j,k,p,sum=0;
    cin>>s;
    int len=s.length();
    dp[0][0][0]=1;
    for(int i=1;i<=len;++i){
        for(int l=0;l<len-i+1;++l){
            int r=l+i-1;
            dp[l][r][0]=i;dp[l][r][1]=i;
            for(int j=l;j<=r;++j){
                dp[l][r][0]=min(dp[l][j][0]+r-j,dp[l][r][0]);
                dp[l][r][1]=min(dp[l][r][1],min(dp[l][j][1],dp[l][j][0])+1+min(dp[j+1][r][1],dp[j+1][r][0]));
            }
            if(i%2==0 && judge(l,r) )
                dp[l][r][0]=min(dp[l][r][0],dp[l][(l+r)/2][0]+1);
        }
    }
    p=min(dp[0][len-1][0],dp[0][len-1][1]);
    cout<<p<<endl;

    return 0;
}