折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) SSSS…S(X个S)。 3. 如果A A’, BB’,则AB A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B) AAACBB,而2(3(A)C)2(B)AAACAAACBB 给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。
Input
仅一行,即字符串S,长度保证不超过100。
Output
仅一行,即最短的折叠长度。
Sample Input
NEERCYESYESYESNEERCYESYESYES
Sample Output
14
HINT
一个最短的折叠为:2(NEERC3(YES))
dp{i,j}表示从i到j最小的字符串长度。
状态转移方程为dp{l,r}=min{r-l+1,dp{l,k}+dp{k+1,r}}/l<=k<r
还要考虑字符串是否可以折叠,若可以折叠
dp{l,r}=min(dp{l,r},dp{l,k}+2+cal((r-l+1)/(k-l+1))}.
public class _1090 {
static String s;
static int[][] f;
static boolean[][] vis;
public static boolean repeat(int l,int r,int li,int ri){ //看有没有折叠部分
int bi=r-l+1;
int si=ri-li+1;
if(bi%si!=0){
return false;
}
for(int i=l;i<=r;++i){
if(s.charAt(i)!=s.charAt((i-l)%si+li)){
return false;
}
}
return true;
}
public static int cal(int a,int b){ //处理10以上折叠部分的数
return String.valueOf(a/b).length();
}
public static int dp(int l,int r){
if(l==r){
return 1;
}
if(vis[l][r]){ //记忆化搜索
return f[l][r];
}
vis[l][r]=true;
int t=r-l+1; //当前的长度
for(int k=l;k<r;++k){
int ld=dp(l,k);
int rd=dp(k+1,r);
t=Math.min(t,ld+rd);
if(repeat(k+1,r,l,k)){ //判断可否折叠
t=Math.min(t,ld+2+cal(r-l+1,k-l+1));
}
}
return f[l][r]=t;
}
public static void main(String[] args){
Scanner cin=new Scanner(System.in);
s=cin.next();
vis=new boolean[s.length()][s.length()];
f=new int[s.length()][s.length()];
System.out.println(dp(0,s.length()-1));
}
}