Jzoj3443 压缩
2017-09-25 19:39
120 查看
一个文本压缩后由若干个单元组成,每个单元由3部分组成:1.正文(小写字母组成的字符串)2.若干个”*”,表示正文的又重复了几次3.单元的结尾符号”$”,显然,对于同一文本,压缩后的表示方法不唯一,但是为了方便,我们要求你采用压缩后字符串最短的压缩方法,如果有多种压缩方法,只需输出任意一种。n<=2000
看到数据范围我们发现可以用dp,设f[i][j]表示目前在第i位,最后一个循环串的长度为j的情况下,最短的长度
那么显然,无论怎么样,有一种转移总是成立的,f[i][j]=min(f[i-j][k]+j+1),这相当于新开了一个循环节
而另一个转移需要满足一个条件,f[i][j]=min(f[i-j][j]+1),当s(i-j+1,i)=s(i-j*2+1,i-j)时,这相当于在循环节里面加入一个*
那么综合下来转移就是n^3的,我们加上两个优化
1.令g[i]为min(f[i][k]),避免每次枚举k
2.判断字串相等用hash
这样我们可以将复杂度将为n^2
接下来说一下如何输出方案
先记录下s[i][j]表示状态i,j的最后一个循环节j循环次数,和上面两种转移对应,s[i][j]=1或者s[i][j]=s[i][i-j]+1
我们令d[i]表示答案为g[i]时,最后一个循环节的循环次数,令r[i]为此循环节的长度,那么求解g[i]时,就可以顺便求解d[i]和r[i]
最后输出即可
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define L long long
using namespace std;
int n,m=0; char str[2010],A[2010];
int f[2010][2010],b[2010],d[2010];
int h[2010],g[2010],s[2010][2010],r[2010];
__attribute__((optimize("-O3")))
inline L gH(int l,int r){ return h[r]-h[l-1]*b[r-l+1]; }
int main(){
freopen("compress.in","r",stdin);
freopen("compress.out","w",stdout);
scanf("%s",str+1); n=strlen(str+1);
for(int i=*b=1;i<=n;++i){
b[i]=b[i-1]*27;
h[i]=h[i-1]*27+str[i]-'a';
}
memset(g,127,sizeof g); *g=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j){
f[i][j]=g[i-j]+j+1; s[i][j]=1;
if(f[i][j]<g[i]){ d[i]=1; r[i]=j; g[i]=f[i][j]; }
if(i>=(j<<1) && gH(i-j+1,i)==gH(i-j*2+1,i-j))
if(f[i][j]>f[i-j][j]+1){
s[i][j]=s[i-j][j]+1;
f[i][j]=f[i-j][j]+1;
if(f[i][j]<g[i])
{ d[i]=s[i][j]; r[i]=j; g[i]=f[i][j]; }
}
g[i]=min(g[i],f[i][j]);
}
for(;n;){
A[m++]='$';
for(int i=1;i<d
;++i) A[m++]='*';
for(int i=n;i>n-r
;A[m++]=str[i--]);
n-=r
*d
;
}
reverse(A,A+m); puts(A);
}
看到数据范围我们发现可以用dp,设f[i][j]表示目前在第i位,最后一个循环串的长度为j的情况下,最短的长度
那么显然,无论怎么样,有一种转移总是成立的,f[i][j]=min(f[i-j][k]+j+1),这相当于新开了一个循环节
而另一个转移需要满足一个条件,f[i][j]=min(f[i-j][j]+1),当s(i-j+1,i)=s(i-j*2+1,i-j)时,这相当于在循环节里面加入一个*
那么综合下来转移就是n^3的,我们加上两个优化
1.令g[i]为min(f[i][k]),避免每次枚举k
2.判断字串相等用hash
这样我们可以将复杂度将为n^2
接下来说一下如何输出方案
先记录下s[i][j]表示状态i,j的最后一个循环节j循环次数,和上面两种转移对应,s[i][j]=1或者s[i][j]=s[i][i-j]+1
我们令d[i]表示答案为g[i]时,最后一个循环节的循环次数,令r[i]为此循环节的长度,那么求解g[i]时,就可以顺便求解d[i]和r[i]
最后输出即可
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define L long long
using namespace std;
int n,m=0; char str[2010],A[2010];
int f[2010][2010],b[2010],d[2010];
int h[2010],g[2010],s[2010][2010],r[2010];
__attribute__((optimize("-O3")))
inline L gH(int l,int r){ return h[r]-h[l-1]*b[r-l+1]; }
int main(){
freopen("compress.in","r",stdin);
freopen("compress.out","w",stdout);
scanf("%s",str+1); n=strlen(str+1);
for(int i=*b=1;i<=n;++i){
b[i]=b[i-1]*27;
h[i]=h[i-1]*27+str[i]-'a';
}
memset(g,127,sizeof g); *g=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j){
f[i][j]=g[i-j]+j+1; s[i][j]=1;
if(f[i][j]<g[i]){ d[i]=1; r[i]=j; g[i]=f[i][j]; }
if(i>=(j<<1) && gH(i-j+1,i)==gH(i-j*2+1,i-j))
if(f[i][j]>f[i-j][j]+1){
s[i][j]=s[i-j][j]+1;
f[i][j]=f[i-j][j]+1;
if(f[i][j]<g[i])
{ d[i]=s[i][j]; r[i]=j; g[i]=f[i][j]; }
}
g[i]=min(g[i],f[i][j]);
}
for(;n;){
A[m++]='$';
for(int i=1;i<d
;++i) A[m++]='*';
for(int i=n;i>n-r
;A[m++]=str[i--]);
n-=r
*d
;
}
reverse(A,A+m); puts(A);
}
相关文章推荐
- 【jzoj5251】【GDOI2018模拟8.11】【决战】【状态压缩动态规划】
- JZOJ3537 【NOIP2013提高组day2】华容道 暴力+压缩路径优化
- 【jzoj4908】【NOIP2016提高组】【愤怒的小鸟】【状态压缩动态规划】
- 【jzoj3632】【汕头市选2014】【舞伴】【状态压缩动态规划】
- 【jzoj3853】【帮助Bsny】【状态压缩动态规划】
- 【jzoj3737】【挖宝藏】【斯坦纳树】【状态压缩动态规划】
- 【jzoj1617】【SCOI2005】【互不侵犯】【状态压缩动态规划】
- java 将指定文件夹递归的进行zip打包压缩
- 修改Apache配置文件开启gzip压缩传输
- asp.net实现文件解压和压缩
- Linux下tar bz gz等压缩包的压缩和解压
- ubuntu下 rar,zip等压缩文件中文件名乱码的解决方案
- jzoj 2544. 【NOIP2011模拟9.3】作弊的发牌者
- JZOJ 4.2 C组 士兵
- InfluxDB存储引擎Time Structured Merge Tree——本质上和LSM无异,只是结合了列存储压缩,其中引入fb的float压缩,字串字典压缩等
- Jzoj4746 树塔狂想曲
- linux压缩和解压缩命令大全
- Java用ZIP格式压缩和解压缩文件
- 【转】Django下载大文件和压缩zip文件
- HDU_1401——同步双向BFS,八进制位运算压缩,map存放hash