传送门
区间动归。
dp[l][r]表示将l到r这一段合并的最小长度。
枚举分割点。得到转移dp[l][r]=min(r-l+1,dp[l][k],dp[k+1][r])
或者后面一段可以由前面一段得到,得到dp[l][r]=min(dp[l][k]+(r-l+1)/(k-l+1)的位数+2)
记忆化水过。
#include<cstring>
#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;
int f[105][105],v[105][105];
char s[105];
int check(int l1,int r1,int l2,int r2){
if ((r2-l2+1)%(r1-l1+1)!=0) return 0;
for (int i=l1,j=l2;j<=r2;i++,j++){
if (i>r1) i=l1;
if (s[i]!=s[j]) return 0;
}
return 1;
}
int get(int x){
int s=0;
for (;x;x/=10) s++;
return s;
}
int dp(int l,int r){
if (l==r) return f[l][r]=1;
if (v[l][r]) return f[l][r];
int tmp=r-l+1;
v[l][r]=1;
for (int i=l;i<r;i++){
tmp=min(tmp,dp(l,i)+dp(i+1,r));
if (check(l,i,i+1,r))
tmp=min(tmp,dp(l,i)+2+get((r-i)/(i-l+1)+1));
}
return f[l][r]=tmp;
}
int main(){
scanf("%s",&s);
printf("%d",dp(0,strlen(s)-1));
}