bzoj1090[SCOI2003]字符串折叠
Description
折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) SSSS…S(X个S)。 3. 如果A A’, BB’,则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。
Input
仅一行,即字符串S,长度保证不超过100。
Output
仅一行,即最短的折叠长度。
Sample Input
NEERCYESYESYESNEERCYESYESYES
Sample Output
14
HINT
一个最短的折叠为:2(NEERC3(YES))
题解
我们记dp[l][r]为从l到r的最短折叠长度。如果没有折叠,那么显然dp[l][r]=min(r-l+1,dp[l][k]+dp[k+1][r])。考虑有折叠的情况。记循环节为l~k,则dp[l][r]=min(dp[l][r],dp[l][k]+2+wei((r-l+1)/(k-l+1))。其中2为括号所占长度,wei函数为循环次数所占长度。
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 char ch[110]; 9 int dp[110][110]; 10 bool used[110][110]; 11 int ans; 12 bool can(int l,int r,int fl,int fr){ 13 if((r-l+1)%(fr-fl+1)!=0) return false; 14 int i,j; 15 for(i=l;i<=r;++i){ 16 if(ch[i]!=ch[(i-l)%(fr-fl+1)+fl]) return false; 17 } 18 return true; 19 } 20 int wei(int x){ 21 int a=0; 22 while(x){ 23 a++;x=x/10; 24 } 25 return a; 26 } 27 int dfs(int l,int r){ 28 if(l==r) return 1; 29 if(used[l][r]) return dp[l][r]; 30 used[l][r]=1; 31 int an=r-l+1; 32 int i,j; 33 for(i=l;i<r;++i){ 34 an=min(an,dfs(l,i)+dfs(i+1,r)); 35 if(can(i+1,r,l,i)){ 36 an=min(an,dfs(l,i)+2+wei((r-i)/(i-l+1)+1)); 37 } 38 } 39 dp[l][r]=an; 40 return dp[l][r]; 41 } 42 int main(){ 43 scanf("%s",ch); 44 int len=strlen(ch); 45 memset(used,0,sizeof(used)); 46 ans=dfs(0,len-1); 47 printf("%d\n",ans); 48 return 0; 49 }