• BZOJ1068 [SCOI2007]压缩 区间动态规划 字符串


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1068


    题目概括

      (其实是复制的)

      给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程。

     

      另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。


    题解

      这又是一道字符串的题目。

      记得有人说过——字符串的题目就是哈希+乱搞????

      言归正传:

      一看就是一道区间动归。

      所以我们用:

        g[i][j]表示禁止更新缓冲,但是允许解压R的情况 (最短值)
        f[i][j]表示允许更新缓冲,但是禁止解压R的情况 (最短值)

      于是只需要写两个记忆化dfs就可以了。

      具体操作看代码。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=50+5;
    char str[N];
    int n,g[N][N],f[N][N];
    // g[i][j]表示禁止更新缓冲,但是允许解压R的情况 
    // f[i][j]表示允许更新缓冲,但是禁止解压R的情况 
    bool can_fold[N][N];
    bool fold_check(int L,int R){
        int len=R-L+1;
        if (len&1)
            return 0;
        int M=L+len/2;
        for (int i=0;i<len/2;i++)
            if (str[L+i]!=str[M+i])
                return 0;
        return 1;
    }
    int G(int L,int R){
        if (L>R)
            return 0;
        if (g[L][R]!=-1)
            return g[L][R];
        g[L][R]=R-L+1;
        for (int i=1;L+i*2-1<=R;i++){
            int M=L+i*2-1;
            if (can_fold[L][M])
                g[L][R]=min(g[L][R],G(L,L+i-1)+1+(R-M));
        }
        return g[L][R];
    }
    int F(int L,int R){
        if (L>R)
            return 0;
        if (f[L][R]!=-1)
            return f[L][R];
        f[L][R]=G(L,R);
        for (int i=L;i<=R;i++)
            f[L][R]=min(f[L][R],min(G(L,i)+1+F(i+1,R),G(L,i)+(R-i)));
        return f[L][R];
    }
    int main(){
        scanf("%s",str+1);
        n=strlen(str+1);
        memset(can_fold,0,sizeof can_fold);
        for (int i=1;i<=n;i++)
            for (int j=i;j<=n;j++)
                can_fold[i][j]=fold_check(i,j);
        memset(f,-1,sizeof f);
        memset(g,-1,sizeof g);
        for (int i=1;i<=n;i++)
            f[i][i]=g[i][i]=1;
        printf("%d",F(1,n));
        return 0;
    } 
  • 相关阅读:
    GUI起头
    最大公约数
    最小公倍数
    最大公约数、最小公倍数
    质数——筛选法
    质数——用已有质数求质数
    质数——6N±1法
    质数——1到n遍历法
    微服务的优势
    收到offer!
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1068.html
Copyright © 2020-2023  润新知