题目大意:折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。2. X(S)是X(X>1)个S连接在一起的串的折叠,记作X(S) 3. 折叠可以嵌套。给一个字符串,求它的最短折叠。
题解:区间dp
f[l][r]
表示
[l,r]
压缩后最短长度,初始值
f[l][r]=r−l+1
转移:枚举区间分割点
k,l≤k<r
(1)不折叠:
f[l][r]=f[l][k]+f[k+1][r]
(2)折叠:
f[l][r]=f[l][k]+2+calc((r−l+1)/(k−l+1))
,要求k+1~r可以由l~k重复得到,其中2为括号长度,calc为总长度/循环节长度即系数所占长度
答案即为 f[1][n]
我的收获:区……间dp
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=105;
char s[M];
int bit,f[M][M];
bool lyd(int l1,int r1,int l2,int r2)//
{
if((r1-l1+1)%(r2-l2+1)!=0) return 0;
for(int i=l1;i<=r1;i++)
if(s[i]!=s[(i-l1)%(r2-l2+1)+l2]) return 0;
return 1;
}
int get(int x)//求位数
{
for(bit=0;x;x/=10,bit++);
return bit;
}
int DP(int l,int r)
{
if(l==r) return 1;
if(f[l][r]!=-1) return f[l][r];
int now=r-l+1;
for(int k=l;k<r;k++)
{
now=min(now,DP(l,k)+DP(k+1,r));//(1)不折叠
if(lyd(k+1,r,l,k)) now=min(now,DP(l,k)+2+get((r-l+1)/(k-l+1)));//(2)折叠
}
return f[l][r]=now;
}
void work(){
scanf("%s",s+1);
memset(f,-1,sizeof(f));
printf("%d\n",DP(1,strlen(s+1)));
}
int main()
{
work();
return 0;
}