bzoj 1090 [SCOI2003]字符串折叠(区间DP)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1090 [SCOI2003]字符串折叠(区间DP)相关的知识,希望对你有一定的参考价值。
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1090
【题意】
给定一个字符串,问将字符串折叠后的最小长度。
【思路】
设f[i][j]表示将区间ij折叠后的最小长度,则有转移式:
f[i][j]=min{ j-i+1,f[i][k]+f[k+1][j],f[i][i+x-1]+2+digit((j-i+1)/x) }
第一项代表不折叠,第二项代表当前不折叠,第三项代表以x长度折叠ij区间,条件是满足ij区间以x为循环节。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 6 const int N = 5e2+10; 7 8 int n; 9 char s[N]; 10 int f[N][N]; 11 12 int digit(int x) 13 { 14 return x<10? 1:(x<100?2:3); 15 } 16 int dp(int l,int r) 17 { 18 int& ans=f[l][r]; 19 if(ans>=0) return ans; 20 if(l==r) return ans=1; 21 int len=r-l+1; ans=len; 22 for(int k=l;k<r;k++) 23 ans=min(ans,dp(l,k)+dp(k+1,r)); 24 for(int x=1;x<=len;x++) if(len%x==0) { 25 int flag=0; 26 for(int i=l;i<=l+x-1;i++) { 27 int j=i+x; 28 while(j<=r) { 29 if(s[i]!=s[j]) { flag=1; break; } 30 j+=x; 31 } 32 if(flag==1) break; 33 } 34 if(!flag) ans=min(ans,dp(l,l+x-1)+2+digit(len/x)); 35 } 36 return ans; 37 } 38 39 int main() 40 { 41 scanf("%s",s); 42 n=strlen(s); 43 memset(f,-1,sizeof(f)); 44 printf("%d\n",dp(0,n-1)); 45 return 0; 46 }
以上是关于bzoj 1090 [SCOI2003]字符串折叠(区间DP)的主要内容,如果未能解决你的问题,请参考以下文章