这道题的题面是这样的:
题目描述
折叠的定义如下:
- 一个字符串可以看成它自身的折叠。记作
S = S
X(S)
是 XX 个S
连接在一起的串的折叠。记作X(S) = SSSS…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
,长度保证不超过 100100。
输出格式
仅一行,即最短的折叠长度。
样例 #1
样例输入 #1
NEERCYESYESYESNEERCYESYESYES
Copy
样例输出 #1
14
Copy
提示
一个最短的折叠为:2(NEERC3(YES))
而还有一道与它类似的题目 :
ZJU 1554 Folding 字符串的压缩
Description
我们定义一个字符串S,假如S由N个T连在一起组成,则我们可以把S压缩这样表示:n(T)。
例如: AAAAA=5(A)
给出一个字符串S,求出他能被压缩的最小长度是多少。(注意,这里的一切字符都要算入长度,包括括号、数字)
S长度小于100
Format
Input
输入一个字符串S
Output
S被压缩后的长度
Samples
输入数据 1
AAAAAAAAAABABABCCD
Copy
输出数据 1
12
Copy
Hint
样例数据被压成:9(A)3(AB)CCD,长度为12
思路
这道题(准确来说是这两道题)的思路是这样的:
- 可以发现,这两题与「一本通 5.1 练习 1」括号配对相似,所以思路也应该和它一样。
-
「一本通 5.1 练习 1」括号配对是用DP,所以这道题也可以用DP。
-
做之前,先要提出它和它上一代之间的关系,即找到递推公式。
- 公式需要分析,而分析的办法有几种,如:分析样例数据,画图理解,
打表。
综上所述,我们得出这道题可以打表用Dp。
而这道题的递推公式就是这样的:
int j=i+l-1;
f[i][j]=j-i+1;
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
for(int k=i;k<j;k++){
int len=k-i+1;
if(l%len!=0) continue;
if(f1(i,k,j)){
f[i][j]=min(f[i][j],f2(l/len)+2+f[i][k]);
}
}
代码是这样的:
#include<bits/stdc++.h>
using namespace std;
struct ll{
long long a,b,c,d,e,k,x,y,z;
}v[102345];
bool qp(ll a,ll b){
return a.a<b.a;
}
int mo=1e9+7,f[1005][1005],ld[1000405],lk=0,m,z[14045],kla,a1,a2,a3,a4;
char uuiuhiuh,zz[10001];
int f2(int x){
if(x<10) return 1;
else if(x==100) return 3;
else return 2;
}
bool f1(int l,int mid,int r){
int x=l;
for(int i=mid+1;i<=r;i++){
if(zz[i]!=zz[x]){
return 0;
}
x++;
if(x==mid+1) x=l;
}
return 1;
}
int main(){
scanf("%s",zz+1);
int n=strlen(zz+1);
for(int l=1;l<=n;l++){
for(int i=1;i+l-1<=n;i++){
int j=i+l-1;
f[i][j]=j-i+1;
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
for(int k=i;k<j;k++){
int len=k-i+1;
if(l%len!=0) continue;
if(f1(i,k,j)){
f[i][j]=min(f[i][j],f2(l/len)+2+f[i][k]);
}
}
}
}
cout<<f[1][n]<<endl;
return 0;
}