dp[i][j] 表示 i-j这一段的最小值,
那么转移方程 dp[i][j] = min(dp[i][i+k]+dp[i+k+1][ j] ,(如果是i--i+k-1 这个子串的重复)min( dp[i][i+k-1] + flag+2 ) flag 为数字的长度 所占位数 )
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 220;
const int inf = 0x7f7f7f7f;
int dp[maxn][maxn];
string str;
int ok(int i,int j,int k)
{
//printf("i=%d j=%d k=%d ",i,j,k);
// cout<<str.substr(i,j-i+1)<<endl;
string tmp=str.substr(i,k);
// cout<<tmp<<endl;
int n=0;
for(i;i+k-1<=j;i+=k)
{
// cout<<"sub "<<str.substr(i,k)<<endl;
if(tmp==str.substr(i,k)) n++;
else return 0;
}
// int n=(j-i+1)/k;
int res=0;
while(n)
{
res++;
n/=10;
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
cin>>str;
int len=str.length();
for(int i=0;i<=len;i++)
{
for(int j=i;j<=len;j++)
dp[i][j]=inf;
dp[i][i]=1;
}
for(int i=0;i<len;i++)
{
for(int j=i-1;j>=0;j--)
{
dp[j][i]=i-j+1;
int tmp=inf;
for(int k=j;k<i;k++)
{
tmp=min(tmp,dp[j][k]+dp[k+1][i]);
}
for(int k=1;k<=i-j+1;k++)
{
if((i-j+1)%k==0)
{
int flag=ok(j,i,k);
// printf("ok i=%d j=%d f=%d\n",j,i,flag);
if(flag) tmp=min(tmp,dp[j][j+k-1]+flag+2);
}
}
//printf("i=%d j=%d tm=%d\n",j,i,tmp);
dp[j][i]=min(dp[j][i],tmp);
//printf("i=%d j=%d dp=%d\n",j,i,dp[j][i]);
}
}
printf("%d\n",dp[0][len-1]);
}
return 0;
}