BZOJ 1090 SCOI2003 字符串折叠 动态规划+Hash

50 篇文章 1 订阅
23 篇文章 0 订阅

题目大意:给定一个字符串,求按照题中所给的压缩方式最短能压缩到多长

区间DP 令f[i][j]表示[i,j]区间内的字符串最短能压缩到多长

普通的区间DP:f[i][j]=min{f[i][k]+f[k+1][j]} (i<=k<=j-1)

此外如果对这段字符串进行压缩,那么我们可以枚举循环节,用Hash来判断

如果k是一个循环节,那么有f[i][j]=min(f[i][j],f[i][i+k-1]+digit[len/k]+2)

其中len=j-i+1,digit表示一个数在十进制下的长度

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 110
#define BASE 151
using namespace std;
typedef unsigned long long ll;
int n,digit[M],f[M][M];
char s[M];
ll hash[M],power[M];
void Pretreatment()
{
	int i;
	for(i=1;i<=n;i++)
		digit[i]=digit[i/10]+1;
	for(power[0]=1,i=1;i<=n;i++)
		power[i]=power[i-1]*BASE;
	for(i=1;i<=n;i++)
		hash[i]=hash[i-1]*BASE+s[i];
}
int main()
{
	int i,j,k,len;
	scanf("%s",s+1);n=strlen(s+1);
	Pretreatment();
	memset(f,0x3f,sizeof f);
	for(i=1;i<=n;i++)
		f[i][i]=1;
	for(len=2;len<=n;len++)
		for(i=1;(j=i+len-1)<=n;i++)
		{
			for(k=i;k<j;k++)
				f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
			for(k=1;k<n;k++)
				if(len%k==0)
				{
					ll hash1=hash[j-k]-hash[i-1]*power[len-k];
					ll hash2=hash[j]-hash[i+k-1]*power[len-k];
					if(hash1!=hash2)
						continue;
					f[i][j]=min(f[i][j],f[i][i+k-1]+digit[len/k]+2);
				}
		}
	cout<<f[1][n]<<endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值