BZOJ-1090字符串折叠 区间DP + Hash

Posted DaD3zZ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",f[1][N]);
    return 0;
}

 

以上是关于BZOJ-1090字符串折叠 区间DP + Hash的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-1090字符串折叠 区间DP + Hash

[bzoj1090][SCOI2003]字符串折叠_区间dp

bzoj1090(区间dp)

BZOJ1090: [SCOI2003]字符串折叠

bzoj1090:[SCOI2003]字符串折叠

BZOJ 1090: [SCOI2003]字符串折叠 区间动归