zoukankan      html  css  js  c++  java
  • 【BZOJ-1090】字符串折叠 区间DP + Hash

    1090: [SCOI2003]字符串折叠

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1127  Solved: 737
    [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))

    Source

    Solution

    区间DP

    f[l][r]表示区间[l,r]最短折叠

    那么我们枚举区间长度,枚举区间左端点,枚举断点

    $f[l][r]=min(r-l+1,f[l][k]+f[k+1][r]);$

    $f[l][r]=min(f[l][r],f[l][k]+2+s);$ 当区间[l,r]能被[l,k]折叠,2为括号,s为系数位数

    判断的时候可以暴力判断,不过那么%来%去太鬼畜了,所以直接用个Hash

    Code

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    char S[110];
    int f[110][110],N;
    #define base 13
    #define ULL unsigned long long
    ULL bin[110],hash[110];
    void Hashtable()
    {
        bin[0]=1; for (int i=1; i<=N; i++) bin[i]=bin[i-1]*base;
        for (int i=1; i<=N; i++) hash[i]=hash[i-1]*base+S[i];
    }
    inline ULL Gethash(int l,int r) {return hash[r]-hash[l-1]*bin[r-l+1];}
    inline int size(int x) {int re=0; while (x) x/=10,re++; return re;}
    inline bool judge(int l,int m,int r)
    {
        if ((r-l+1)%m) return 0;
        int tl=(r-l+1)/m; ULL t=Gethash(l,l+tl-1);
        for (int i=l; i<=r; i+=tl)
            if (Gethash(i,i+tl-1)!=t) return 0;
        return 1;
    }
    int main()
    {
        scanf("%s",S+1); N=strlen(S+1);
        Hashtable();
        for (int i=1; i<=N; i++)
            for (int j=1; j<=N; j++)
                if (j+i-1<=N)
                    {
                        int l=j,r=j+i-1;
                        f[l][r]=r-l+1;
                        for (int k=1; k<=i; k++)
                            {
                                f[l][r]=min(f[l][r],f[l][l+k-1]+f[l+k][r]);
                                if (judge(l,k,r)) f[l][r]=min(f[l][r],2+size(k)+f[l][l+(r-l+1)/k-1]);
                            }
                    }
        printf("%d
    ",f[1][N]);
        return 0;
    }
  • 相关阅读:
    Python 学习笔记(二)开发环境的搭建
    Python 学习笔记(一)Python 简介
    android.os.NetworkOnMainThreadException
    Android Call requires API level 11 (current min is 8)的解决方案
    Linux命令top 详解
    主流nosql数据库对比
    MongoDB的常用命令
    MongoDB添加用户验证
    MongoDB
    html介绍
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5890014.html
Copyright © 2011-2022 走看看