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 }

 

posted @ 2017-07-28 03:49  太阳星人FxxL  阅读(312)  评论(0编辑  收藏  举报