题目大意:给定一个字符串,求按照题中所给的压缩方式最短能压缩到多长
区间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; }
BZOJ 1090 SCOI2003 字符串折叠 动态规划+Hash
原文地址:http://blog.csdn.net/popoqqq/article/details/43061047