题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1090
思路
据七爷说此题是URAL原题,并且原题还要输出最小的折叠后的字符串?
看来以后要多刷URAL。。。
一眼就能发现这是个DP题,用 f[L][R] 表示 [L,R] 区间折叠的最小长度,很容易得到DP方程:
f[L][R]=min{R−L+1,f[L][k]+f[k+1][R]},L<=k<R
但是有个特殊情况,即 [k+1,R] 部分可以由[L,k]部分重复折叠而来,此时 f[L][R]=min{f[L][k]+2+|R−L+1k−L+1|},|x|= 数字 x <script id="MathJax-Element-265" type="math/tex">x</script>的长度
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 110
using namespace std;
int f[MAXN][MAXN]; //f[L][R]=[L,R]的最短折叠长度
char s[MAXN];
bool check(int L1,int R1,int L2,int R2)
{
int p=L2;
if((R2-L2+1)%(R1-L1+1)) return false;
while(p<=R2)
{
for(int i=1;i<=R1-L1+1;i++)
if(s[L1+i-1]!=s[p+i-1])
return false;
p+=(R1-L1+1);
}
return true;
}
int getlen(int x) //求出数字x的长度
{
int len=0;
if(!x) return 1;
while(x)
{
x/=10;
len++;
}
return len;
}
int dp(int L,int R) //求f[L][R]
{
if(f[L][R]!=-1) return f[L][R];
if(L==R)
return f[L][R]=1;
f[L][R]=R-L+1;
for(int k=L;k<R;k++)
{
f[L][R]=min(f[L][R],dp(L,k)+dp(k+1,R));
if(check(L,k,k+1,R)) //[k+1,R]部分可以由[L,k]重复表示
{
f[L][R]=min(f[L][R],dp(L,k)+2+getlen((R-L+1)/(k-L+1)));
}
}
return f[L][R];
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%s",s+1);
int n=strlen(s+1);
printf("%d\n",dp(1,n));
return 0;
}