B1090 [SCOI2003]字符串折叠 区间dp

Posted dukelv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B1090 [SCOI2003]字符串折叠 区间dp相关的知识,希望对你有一定的参考价值。

又一道区间dp,和上一篇类似,但是比他简单,这个只有两种转移方法,不是很复杂。直接判断是否为重复的串就行。

题干:

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

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < 0 || c > 9)
        if(c == -) op = 1;
    x = c - 0;
    while(c = getchar(), c >= 0 && c <= 9)
        x = x * 10 + c - 0;
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar(-), x = -x;
    if(x >= 10) write(x / 10);
    putchar(0 + x % 10);
}
char s[1100];
int f[1100][1100],n,l;
bool get(int x1,int y1,int x2,int y2)
{
    if((y2 - x1 + 1) % (y1 - x1 + 1) != 0)
    return false;
    int len = y1 - x1 + 1;
    duke(i,x2,y2)
    {
        if(s[i] != s[i - len])
        return false;
    }
    return true;
}
int cal(int k)
{
    int cnt = 0;
    while(k)
    {
        cnt++;
        k /= 10;
    }
    return cnt;
}
int main()
{
    memset(f,0x3f,sizeof(f));
    scanf("%s",s + 1);
    n = strlen(s + 1);
    duke(i,0,n)
    f[i][i] = 1;
    duke(l,1,n - 1)
    {
        duke(i,1,n - 1)
        {
            int j = i + l;
            f[i][j] = (j - i + 1);
            duke(k,i,j - 1)
            {
                if(!get(i,k,k + 1,j))
                    f[i][j] = min(f[i][j],f[i][k] + f[k + 1][j]);
                else
                    f[i][j] = min(f[i][j],f[i][k] + 2 + cal((l + 1) / (k - i + 1)));
            }
        }
    }
    printf("%d
",f[1][n]);
    return 0;
}

 

以上是关于B1090 [SCOI2003]字符串折叠 区间dp的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1090 [SCOI2003]字符串折叠(区间DP)

[luogu1090 SCOI2003] 字符串折叠(区间DP+hash)

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

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

[SCOI 2003] 字符串折叠

[SCOI2003] 字符串折叠