BZOJ 1090 字符串折叠(区间DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1090

题意:字符串AAAAAAAAAABABABCCD的最短折叠为9(A)3(AB)CCD,注意数字的长度和圆括号都算最后长度。求一种折叠方式使得总长度最小。

思路:记忆化搜索。

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 char s[500005],a[500005];
 7 int f[5005][5005];
 8 bool ok(int l,int r,int len){
 9     int L=0;
10     for (int i=l;i<=l+len-1;i++)
11      a[++L]=s[i];
12     int num=(r-l+1)/len;
13     for (int i=1;i<=num;i++)
14      for (int j=1;j<=len;j++)
15       if (a[j]!=s[l+(i-1)*len+j-1]) return 0;
16     return 1;   
17 }
18 int cal(int x){
19     if (x<10) return 1;
20     if (x<=99) return 2;
21     return 3;
22 }
23 int dp(int l,int r){
24     if (f[l][r]!=-1) return f[l][r];
25     if (l==r) return 1;
26     int len=r-l+1;
27     f[l][r]=len;
28     for (int i=l;i<r;i++)
29      f[l][r]=std::min(f[l][r],dp(l,i)+dp(i+1,r));
30     for (int i=1;i<len;i++)
31      if (len%i==0&&ok(l,r,i)) f[l][r]=std::min(f[l][r],dp(l,l+i-1)+cal(len/i)+2);
32     return f[l][r];
33 }
34 int main(){
35     scanf("%s",s+1);
36     int n=strlen(s+1);
37     for (int i=1;i<=n;i++)
38      for (int j=1;j<=n;j++)
39       f[i][j]=-1;
40     printf("%d\n",dp(1,n));
41 }

 

posted @ 2016-06-02 17:43  GFY  阅读(145)  评论(0编辑  收藏  举报