[SCOI2003]字符串折叠

题目描述

折叠的定义如下:

  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。

输入输出格式

输入格式:

 

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 
NEERCYESYESYESNEERCYESYESYES
输出样例#1: 
14

说明

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

 

分析:

本题显然是区间DP, 用F[i][j]表示从第i个字符到第j个字符的最小长度,然后枚举中间断点,进行状态转移即可。

 

CODE:

 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 const int M=105;
 8 char a[M];
 9 int f[M][M],n;
10 inline int read(){
11     char c=getchar();
12     int ans=0;
13     while (c<'0'||c>'9')
14     c=getchar();
15     while (c>='0'&&c<='9') 
16     ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();
17     return ans;
18 }
19 int count(int x){
20     int ans=0;
21     for (int i=x;i;i/=10) ans++;
22     return ans;
23 }
24 int main(){
25     scanf("%s",a+1);
26     n=strlen(a+1);
27     for (int i=1;i<=n;i++) 
28     f[i][i]=1;
29     for (int l=1;l<n;l++)
30         for (int i=1;i+l<=n;i++){
31             int j=i+l;
32             f[i][j]=l+1;
33             for (int k=i;k<j;k++) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
34             for (int k=1;k<=(l+1)/2;k++){
35                 if ((l+1)%k) continue;
36                 bool flag=1;
37                 for (int u=i+k;u<=j;u++)
38                     if (a[u]!=a[i+(u-i)%k]){flag=0;break;}
39                 if (flag) f[i][j]=min(f[i][j],count((l+1)/k)+2+f[i][i+k-1]);
40             }
41         }
42     printf("%d",f[1][n]);
43     return 0;
44 }

 

posted @ 2019-07-10 12:41  Sword_Art_Online  阅读(316)  评论(0编辑  收藏  举报