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

来源:互联网 发布:怎样在淘宝上买弩 编辑:程序博客网 时间:2024/06/06 07:44

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

区间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 151using 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;}


1 0