zoukankan      html  css  js  c++  java
  • bzoj1090 [SCOI2003]字符串折叠

    1090: [SCOI2003]字符串折叠

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1718  Solved: 1146
    [Submit][Status][Discuss]

    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))

    分析:一开始觉得和bzoj1068差不多.用那道题的状态去推状态转移方程发现不是那么容易推.因为这里括号必须要是匹配的,而那一题并不要求R,M匹配.

       实际上这道题还要简单一些,区间dp的基本状态表示方法:f[l][r]就能够转移.

       两种方式:1.f[l][r] = min{f[i][k] + f[k+1][r]}.  2.f[l][r] = min{f[l][k] + 2 + (r - l + 1) / (k - l + 1)的结果的位数}.这两个转移分别是将子区间合并和将字符串折叠.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    char s[110];
    int n,f[110][110];
    
    int cal(int x)
    {
        if (x >= 1 && x <= 9)
            return 1;
        if (x >= 10 && x <= 99)
            return 2;
        if (x >= 100)
            return 3;
    }
    
    bool check(int l,int mid,int r)
    {
        int x = l;
        for (int i = mid + 1; i <= r; i++)
        {
            if (s[x] != s[i])
                return false;
            x++;
            if (x == mid + 1)
                x = l;
        }
        return true;
    }
    
    int main()
    {
        scanf("%s",s + 1);
        n = strlen(s + 1);
        for (int l = 1; l <= n; l++)
        {
            for (int i = 1; i + l - 1 <= n; i++)
            {
                int j = i + l - 1;
                f[i][j] = j - i + 1;
                for (int k = i; k < j; k++)
                    f[i][j] = min(f[i][j],f[i][k] + f[k + 1][j]);
                for (int k = i; k < j; k++)
                {
                    int len = k - i + 1;
                    if(l % len != 0)
                        continue;
                    if (check(i,k,j))
                        f[i][j] = min(f[i][j],f[i][k] + 2 + cal(l / len));
                }
            }
        }
        printf("%d
    ",f[1][n]);
    
        return 0;
    }
  • 相关阅读:
    linux umask使用详解
    Linux 解压压缩命令
    linux命令:tail 命令
    linux命令:head 命令
    linux下cat命令详解
    linux命令:rm 命令
    linux命令:mv命令
    Linux 的cp命令
    文件权限详解
    Linux ls命令参数详解
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8455192.html
Copyright © 2011-2022 走看看