[SCOI2003]字符串折叠

原题:[SCOI2003]字符串折叠


 

啊没错又是dp

啊没错又是区间dp


 

设 dp[i][j] 为区间 i~j 的最短折叠长度

转移 , 情况有两种

第一种是把两个已经折叠好的区间合并

另一种是把这个区间折叠掉

对于第一种 , 很一般的枚举断点然后合并

对于后一种呐?


枚举折叠后的长度(不算括号和系数的长度)

因为是要折掉整个区间 , 所以要枚举的长度是总长度的因数 , 很显然只需要枚举总长度的一半

然后呐 , 怎么检测能否折叠?

写一个函数 , 叫他 check() 吧

就来比较暴力的判断能否折来


 

对于系数的长度

我写了一个divide() 函数 , 不过因为数据范围只有100 , 所以最多只有三种情况 , 分别判断一下就好了

 

代码 :

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define APART puts("----------------------")
 8 #define debug 1
 9 #define FILETEST 1
10 #define inf 1010
11 #define ll long long
12 #define ha 998244353
13 #define INF 0x7fffffff
14 #define INF_T 9223372036854775807
15 #define DEBUG printf("%s %d\n",__FUNCTION__,__LINE__)
16 
17 namespace chino{
18 
19 inline void setting(){
20 #if FILETEST
21     freopen("_test.in", "r", stdin);
22     freopen("_test.me.out", "w", stdout);
23 #endif
24     return;
25 }
26 
27 inline int read(){
28     char c = getchar(), up = c; int num = 0;
29     for(; c < '0' || c > '9'; up = c, c = getchar());
30     for(; c >= '0' && c <= '9'; num = (num << 3) + (num << 1) + (c ^ '0'), c = getchar());
31     return  up == '-' ? -num : num;
32 }
33 
34 int n;
35 char s[inf];
36 int dp[inf][inf]; 
37 
38 using std::min;
39 
40 inline bool check(int l, int r, int k){
41     for(int i = 0; i < k; i++){
42         for(int j = i; j + k + l <= r; j += k){
43             if(s[j + l] != s[j + l + k])
44                 goto A;
45         }
46     }
47     return 1;
48 A:    return 0;
49 }
50 
51 inline int divide(int num){
52     char s[5] = "";
53     sprintf(s, "%d", num);
54     return strlen(s);
55 }
56 
57 inline int main(){
58     memset(dp, 10, sizeof dp);
59     scanf("%s", s + 1);
60     n = strlen(s + 1);
61     for(int l = n; l; l--){
62         dp[l][l] = 1;
63         for(int r = l + 1; r <= n; r++){
64             int len = r - l + 1;
65             dp[l][r] = len;
66             for(int k = l; k < r; k++)
67                 dp[l][r] = min (dp[l][r], dp[l][k] + dp[k + 1][r]);
68             for(int k = 1; k <= (len >> 1); k++){
69                 if(len % k == 0 && check(l, r, k))
70                     dp[l][r] = min (dp[l][r], dp[l][k + l - 1] + 2 + divide(len / k));
71             }
72         }
73     }
74     printf("%d\n", dp[1][n]);
75     return 0;
76 }
77 
78 }//namespace chino
79 
80 int main(){return chino::main();}

 

posted @ 2019-09-29 21:37  ChiaroShiro  阅读(180)  评论(0编辑  收藏  举报