您的位置:首页 > 其它

bzoj 1068: [SCOI2007]压缩

2017-08-16 22:17 435 查看

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.....其实不用,还好有人和我写一样的...

我们明确:我们只需要知道M的位置即可确定状态

所以我们定义f[i][j]为前i个字符,M在j这个位置时的最小长度

考虑从f[i]->f[i+1]

显然我们可以直接加上原字符串的一个 f[i+1][j]=min(f[i][j]+1)

或者我们可以新建一个M f[i][i]=min(f[i][j]+1)

也可以弄一个R,相当于选定i和i+1这个位置作对称 f[i+i-j][j]=min(f[i][j]+1) 前提得满足(S[j]-S[i])==(S[i+1]+S[i+i-j])

这个判等可以预处理出来

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
using namespace std;
const int N=205;
int f

,can

;char s
;
bool check(int i,int j){
int p1=i-j+1,p2=i+1;
for(int k=1;k<=j;k++)
if(s[p1]!=s[p2])return false;
else p1++,p2++;
return true;
}
void work()
{
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=1;i<=n;i++){
for(int j=2;i-j>=0 && i+j<=n;j++){
if(check(i,j))can[i][j]=true;
}
}
memset(f,127/3,sizeof(f));
f[0][0]=0;
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
f[i][i]=min(f[i][i],f[i][j]+1);
f[i+1][j]=min(f[i+1][j],f[i][j]+1);
if(can[i][i-j])
f[i+i-j][j]=min(f[i+i-j][j],f[i][j]+1);
}
}
int ans=N;
for(int i=0;i<=n;i++)
if(f
[i]<ans)
ans=f
[i];
printf("%d\n",ans);
}

int main()
{
freopen("compress.in","r",stdin);
freopen("compress.out","w",stdout);
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: