1068: [SCOI2007]压缩
Description
给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程:
另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。
Input
输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。
Output
输出仅一行,即压缩后字符串的最短长度。
Sample Input
bcdcdcdcdxcdcdcdcd
Sample Output
12
HINT
在第一个例子中,解为aaaRa,在第二个例子中,解为bMcdRRxMcdRR。
【限制】
100%的数据满足:1<=n<=50 100%的数据满足:1<=n<=50
区间DP
对于每个区间l,r,我们分 压缩后 含M或不含M 两种情况(用t=1或0表示)。。。
对于每一个区间(不分含不含M的情况),
我们可以把区间前一段压缩(含不含M 视整个区间是否含M),后一段作为缓冲串
对于压缩后含M的情况,
我们可以把区间分为两段都拿去压缩,然后在压缩完的两段间加一个M。。。
特殊的,对于前半段与后半段相同的区间,
我们可以在 前半段不含M的压缩串后加R
(即压缩串长度可为 前半段不含M的压缩串长度+1)
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define MaxN 51 char s[MaxN]; int len,f[MaxN][MaxN][2]; bool check(int l,int r){ int len=r-l+1; if (len%2) return false; int mid=(l+r)/2; int j=mid+1; for (int i=l;i<=mid;++i){ if (s[i]!=s[j]) return false; ++j; } return true; } int calc(int l,int r,int t){ if (l==r) f[l][r][t]=1; if (f[l][r][t]) return f[l][r][t]; int ans=r-l+1; for (int i=l;i<r;++i){ ans=min(ans,calc(l,i,t)+r-i); if (t) ans=min(ans,calc(l,i,1)+calc(i+1,r,1)+1); } if (check(l,r)) ans=min(ans,calc(l,(l+r)/2,0)+1); f[l][r][t]=ans; return f[l][r][t]; } int main(){ scanf("%s",s+1); len=strlen(s+1); printf("%d\n",calc(1,len,1)); }