Codeforces 852F String Compression
题目
OvO http://codeforces.com/contest/825/problem/F
题解
KMP+DP
十分优雅地利用了KMP的fail数组
fail[k]表示第k个后缀的的fail组数
dp[i]表示到第i个前缀的最优解
由于KMP的fail数组中的fail[i]能用来表达这个字符串的第i个前缀的后缀与这个字符串的前缀的最大匹配长度,所以可以用来在O(1)的时间内计算一个字符串整体作行程编码的最短长度。calcu表达了该过程。
则状态转移方程为 dp[i]=min(dp[i],dp[j]+calcu(j+1,i-(j+1)+1));
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cmath> 5 #include <algorithm> 6 #include <map> 7 8 using namespace std; 9 10 typedef long long ll; 11 typedef unsigned long long ull; 12 13 const int M=8004; 14 15 int lv[M]; 16 int fail[M][M]; 17 char s[M]; 18 int ls; 19 int dp[M]; 20 21 int getLv(int spl) 22 { 23 int ret=0; 24 while(spl) 25 { 26 spl/=10; 27 ret++; 28 } 29 return ret; 30 } 31 32 void init() 33 { 34 int i,j,k; 35 for(i=1;i<=M;i++) 36 lv[i]=getLv(i); 37 for(k=0;k<ls;k++) 38 { 39 j=-1; fail[k][0]=-1; 40 for(i=1;k+i<=ls;i++) 41 { 42 while(j>=0 && s[k+i-1]!=s[k+j]) 43 j=fail[k][j]; 44 j++; 45 fail[k][i]=j; 46 } 47 } 48 // for(i=0;i<=ls;i++) 49 // cout<<fail[0][i]<<' '; 50 // cout<<endl; 51 } 52 53 int calcu(int st,int len) 54 { 55 if(len==2 && s[st]==s[st+1]) 56 return 2; 57 int ret,tmp; 58 tmp=fail[st][len]; 59 // cout<<st<<' '<<len<<' '<<tmp<<endl; 60 if(tmp<(len+1)/2 || len%(len-tmp)!=0) 61 ret=1+len; 62 else 63 ret=lv[len/(len-tmp)]+(len-tmp); 64 return ret; 65 } 66 67 void solve() 68 { 69 int i,j; 70 for(i=0;i<ls;i++) 71 { 72 dp[i]=min(i+1+1,calcu(0,i+1)); 73 for(j=0;j<i;j++) 74 dp[i]=min(dp[i],dp[j]+calcu(j+1,i-(j+1)+1)); 75 } 76 cout<<dp[ls-1]<<endl; 77 } 78 79 int main() 80 { 81 int i,j; 82 cin>>s; 83 ls=strlen(s); 84 init(); 85 solve(); 86 return 0; 87 }