1068: [SCOI2007]压缩
Submit: 1725 Solved: 1108
[Submit][Status][Discuss]
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,然就是想了我半个小时
设f[i][j][0/1],表示区间[i,j],默认i-1有标志M,0/1表示区间内是否存在标志M
处理三种情况:
1、f[i][j][0]=min{f[i][k][0]+j-k}
2、ch[i~mid]==ch[mid+1~j]重复判定成立(即可以标记R),f[i][j][0]=f[i][mid][0]+1
3、进行M标记,f[i][j][1]=min{min(f[i][k][0],f[i][k][1])+1+min(f[k+1][j][0],f[k+1][j][1])}
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 char ch[100]; 7 int n; 8 int f[100][100][2]; 9 10 bool check(int l,int r) 11 { 12 int mid=(l+r)>>1; 13 for(int i=0;i<mid-l+1;i++) 14 if(ch[l+i]!=ch[mid+1+i]) 15 return false; 16 return true; 17 } 18 19 int main() 20 { 21 scanf("%s",ch+1); 22 n=strlen(ch+1); 23 for(int i=n;i>=1;i--) 24 for(int j=i;j<=n;j++) 25 { 26 f[i][j][0]=f[i][j][1]=j-i+1; 27 for(int k=i;k<j;k++) f[i][j][0]=min(f[i][j][0],f[i][k][0]+j-k); 28 if((j-i+1)%2==0&&check(i,j)) f[i][j][0]=f[i][(i+j)>>1][0]+1; 29 for(int k=i;k<j;k++) f[i][j][1]=min(min(f[i][k][0],f[i][k][1])+1+min(f[k+1][j][0],f[k+1][j][1]),f[i][j][1]); 30 } 31 printf("%d ",min(f[1][n][0],f[1][n][1])); 32 return 0; 33 }