zoukankan      html  css  js  c++  java
  • BZOJ1090 [SCOI2003]字符串折叠 区间动态规划 字符串

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

    去博客园看该题解


    题目传送门 - BZOJ1090


    题意概括

      折叠的定义如下:

        1. 一个字符串可以看成它自身的折叠。记作S

        2. X(S)是X(X>1)个S连接在一起的串的折叠。

      n<=100.让你求折叠之后的最小长度。


    题解

      (据说字符串的题有通用做法?——hash+乱搞??)

      首先预处理出从第i个位置开始的连续j个字符最多重复了几次。

      可以用哈希,但是数据范围小,直接暴力匹配就可以了。

      然后,区间动归,记忆化dfs,dp[i][j]表示i~j这一段最少可以折叠成多少。

      具体的状态转移见代码的dfs段。


    代码

    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int N=100+5;
    const int Inf=10000;
    char str[N];
    int n;
    int dp[N][N],match[N][N];
    int num_digit(int x){
        int ans=0;
        while (x)
            ans++,x/=10;
        return ans;
    }
    int dfs(int L,int R){
        if (L>R)
            return 0;
        if (dp[L][R]!=-1)
            return dp[L][R];
        dp[L][R]=dfs(L+1,R)+1;
        for (int i=1;L+i-1<=R;i++)
            for (int j=2;j<=match[L][i]&&L+i*j<=R+1;j++)
                dp[L][R]=min(dp[L][R],dfs(L,L+i-1)+num_digit(j)+2+dfs(L+i*j,R));
        return dp[L][R];
    }
    int main(){
        scanf("%s",str+1);
        n=strlen(str+1);
        for (int i=1;i<=n;i++)//枚举位置 
            for (int j=1;i+j-1<=n;j++){//枚举长度 
                match[i][j]=0;
                for (int k=i+j;k<=n+1;k++){
                    if ((k-i)%j==0)
                        match[i][j]++;
                    if (str[k]!=str[k-j])
                        break;
                }
            }
        memset(dp,-1,sizeof dp);
        for (int i=1;i<=n;i++)
            dp[i][i]=1;
        printf("%d",dfs(1,n));
        return 0;
    }
  • 相关阅读:
    windows cmd command line 命令
    windows cmd color setup
    二进制中1的个数
    斐波拉契数列
    旋转数组的最小数字
    用两个栈实现队列
    重建二叉树
    Bootstrap学习笔记(三) 网格系统
    Bootstrap学习笔记(二) 表单
    Bootstrap学习笔记(一) 排版
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1090.html
Copyright © 2011-2022 走看看