题目描述
折叠的定义如下:
- 一个字符串可以看成它自身的折叠。记作S = S
- X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) = SSSS…S(X个S)。
-
如果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。
输出格式:
仅一行,即最短的折叠长度。
输入输出样例
说明
一个最短的折叠为: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 }