BZOJ 1090 字符串折叠(区间DP)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1090
题意:字符串AAAAAAAAAABABABCCD的最短折叠为9(A)3(AB)CCD,注意数字的长度和圆括号都算最后长度。求一种折叠方式使得总长度最小。
思路:记忆化搜索。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 char s[500005],a[500005]; 7 int f[5005][5005]; 8 bool ok(int l,int r,int len){ 9 int L=0; 10 for (int i=l;i<=l+len-1;i++) 11 a[++L]=s[i]; 12 int num=(r-l+1)/len; 13 for (int i=1;i<=num;i++) 14 for (int j=1;j<=len;j++) 15 if (a[j]!=s[l+(i-1)*len+j-1]) return 0; 16 return 1; 17 } 18 int cal(int x){ 19 if (x<10) return 1; 20 if (x<=99) return 2; 21 return 3; 22 } 23 int dp(int l,int r){ 24 if (f[l][r]!=-1) return f[l][r]; 25 if (l==r) return 1; 26 int len=r-l+1; 27 f[l][r]=len; 28 for (int i=l;i<r;i++) 29 f[l][r]=std::min(f[l][r],dp(l,i)+dp(i+1,r)); 30 for (int i=1;i<len;i++) 31 if (len%i==0&&ok(l,r,i)) f[l][r]=std::min(f[l][r],dp(l,l+i-1)+cal(len/i)+2); 32 return f[l][r]; 33 } 34 int main(){ 35 scanf("%s",s+1); 36 int n=strlen(s+1); 37 for (int i=1;i<=n;i++) 38 for (int j=1;j<=n;j++) 39 f[i][j]=-1; 40 printf("%d\n",dp(1,n)); 41 }