题目大意:给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程
题解: 发现f[i][j]无法转移,加一维t表示[l,r]中有无M分割开,约定L−1处一定有一个M,或L−1=0
转移分三种
f[l][r][t]=min(f[l][r][t],f[l][k][t]+r−k) 只压缩前一段
如果[l,r]有M
f[l][r][t]=min(f[l][r][1],f[l][k][1]+f[k+1][r][1]+1)枚举M的位置为分割点进行转移,所以+1
如果字符串长度为偶数,且前半串等于后半串
f[l][r][t]=min(f[l][(l+r)>>1][0]+1)后半串用1个R替代
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=105;
char s[M];
int f[M][M][2];
bool same(int l,int r) {
int len=r-l+1;
if(len%2) return 0;
int mid=(l+r)>>1;
for(int i=l,j=mid+1;i<=mid;i++,j++) if(s[i]!=s[j]) return 0;
return 1;
}
int DP(int l,int r,bool t)
{
if(l==r) return 1;
if(f[l][r][t]!=-1) return f[l][r][t];
int now=r-l+1;
if(t) for(int k=l;k<r;k++) now=min(now,DP(l,k,1)+DP(k+1,r,1)+1);
for(int k=l;k<r;k++) now=min(now,DP(l,k,t)+r-k);
if(same(l,r)) now=min(now,DP(l,(l+r)>>1,0)+1);
return f[l][r][t]=now;
}
void work(){
scanf("%s",s+1);
memset(f,-1,sizeof(f));
printf("%d\n",DP(1,strlen(s+1),1));
}
int main()
{
work();
return 0;
}