bzoj1090[SCOI2003]字符串折叠

传送门

Description

折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S  S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S)  SSSS…S(X个S)。 3. 如果A  A’, BB’,则AB  A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B)  AAACBB,而2(3(A)C)2(B)AAACAAACBB 给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。

Input

仅一行,即字符串S,长度保证不超过100。

Output

仅一行,即最短的折叠长度。

Sample Input

NEERCYESYESYESNEERCYESYESYES

Sample Output

14

HINT

一个最短的折叠为:2(NEERC3(YES))

题解

我们记dp[l][r]为从l到r的最短折叠长度。如果没有折叠,那么显然dp[l][r]=min(r-l+1,dp[l][k]+dp[k+1][r])。考虑有折叠的情况。记循环节为l~k,则dp[l][r]=min(dp[l][r],dp[l][k]+2+wei((r-l+1)/(k-l+1))。其中2为括号所占长度,wei函数为循环次数所占长度。

代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 using namespace std;
 8 char ch[110];
 9 int dp[110][110];
10 bool used[110][110];
11 int ans;
12 bool can(int l,int r,int fl,int fr){
13     if((r-l+1)%(fr-fl+1)!=0)  return false;
14     int i,j;
15     for(i=l;i<=r;++i){
16         if(ch[i]!=ch[(i-l)%(fr-fl+1)+fl])  return false;
17     }
18     return true;
19 }
20 int wei(int x){
21     int a=0;
22     while(x){
23         a++;x=x/10;
24     }
25     return a;
26 }
27 int dfs(int l,int r){
28     if(l==r)  return 1;
29     if(used[l][r])  return dp[l][r];
30     used[l][r]=1;
31     int an=r-l+1;
32     int i,j;
33     for(i=l;i<r;++i){
34         an=min(an,dfs(l,i)+dfs(i+1,r));
35         if(can(i+1,r,l,i)){
36             an=min(an,dfs(l,i)+2+wei((r-i)/(i-l+1)+1));
37         }
38     }
39     dp[l][r]=an;
40     return dp[l][r];
41 }
42 int main(){
43     scanf("%s",ch);
44     int len=strlen(ch);
45     memset(used,0,sizeof(used));
46     ans=dfs(0,len-1);
47     printf("%d\n",ans);
48     return 0;
49 }

 

 

posted @ 2018-06-11 17:59  lazytear  阅读(110)  评论(0编辑  收藏  举报