BZOJ系列1090《[SCOI2003]字符串折叠》题解

来源:互联网 发布:如何查看网站seo 编辑:程序博客网 时间:2024/06/05 17:16

Description

折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S  S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S)  SSSS…S(X个S)。 3. 如果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。

Input

仅一行,即字符串S,长度保证不超过100。

Output

仅一行,即最短的折叠长度。

Sample Input

NEERCYESYESYESNEERCYESYESYES

Sample Output

14

HINT

一个最短的折叠为:2(NEERC3(YES))


   区间动规,f[i][j]表示该范围内可以组成的最短折叠:f[i][j]=f[i][k]+f[k+1][j];(i<=k<=j)。而且还要有特殊的折叠,如果i到j内的一个子串可以折叠为另一个子串,需要判断并计算这个长子串折叠为短子串的折叠数x所占的格数,不要忘记加上短子串与+2(括号)。

我还是太弱了,刚开始写了个递推型的DP,发现很崩溃,就只能换成记忆化搜索了,但是发现记忆化搜索写区间DP确实挺好的。

代码如下:

#include<iostream>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;char s[110];int f[110][110];bool m[110][110];bool lyd(int l1,int r1,int l2,int r2)//判断一个区间是否能折叠为另一个区间。{    if((r1-l1+1)%(r2-l2+1)!=0) return 0;    for(int i=l1;i<=r1;i++)        if(s[i]!=s[(i-l1)%(r2-l2+1)+l2]) return 0;    return 1; }int get(int x)//计算数字的长度。{    int t=0;    while(x)    {        x/=10;        t++;    }    return t;}int DP(int l,int r){    if(l==r) return 1;    if(m[l][r]) return f[l][r];     m[l][r]=1;    int now=r-l+1;    for(int i=l;i<r;i++)    {        now=min(now,DP(l,i)+DP(i+1,r));        if(lyd(i+1,r,l,i)) now=min(now,DP(l,i)+2+get((r-i)/(i-l+1)+1));//+2表示括号长度?    }    return f[l][r]=now;} int main(){    scanf("%s",s);    printf("%d\n",DP(0,strlen(s)-1));    return 0;}

0 0
原创粉丝点击