BZOJ 1090 字符串折叠(区间DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1090

题意:字符串AAAAAAAAAABABABCCD的最短折叠为9(A)3(AB)CCD,注意数字的长度和圆括号都算最后长度。求一种折叠方式使得总长度最小。

思路:f[L][R]=min(R-L+1,f[L][i]+f[i+1][R]),另外若[L,R]能由[i+1,R]重复若干次,则也可用折叠后的长度更新f[L][R]。

char s[N];
int f[N][N],n;

int OK(int a,int b,int c,int d)
{
    int x=b-a+1;
    int y=d-c+1;
    if(x%y) return 0;
    int i,j,k;
    for(i=1;i<=x/y;i++)
    {
        for(j=(i-1)*y+1,k=c;j<=i*y;j++,k++)
        {
            if(s[j+a-1]!=s[k]) return 0;
        }
    }
    return 1;

}

int cal(int x)
{
    if(x<10) return 1;
    if(x>=10&&x<=99) return 2;
    return 3;
}

int DFS(int L,int R)
{
    if(L==R) return 1;
    if(f[L][R]!=-1) return f[L][R];
    f[L][R]=R-L+1;

    int i;
    for(i=L;i<R;i++)
    {
        f[L][R]=min(f[L][R],DFS(L,i)+DFS(i+1,R));
    }

    for(i=L;i<R;i++) if(OK(L,i,i+1,R))
    {
        int x=R-L+1;
        int y=R-i;
        int t=cal(x/y);
        f[L][R]=min(f[L][R],t+2+DFS(i+1,R));
    }

    return f[L][R];
}

int main()
{
    RD(s+1); n=strlen(s+1); clr(f,-1);
    PR(DFS(1,n));
}

BZOJ 1090 字符串折叠(区间DP),布布扣,bubuko.com

时间: 2024-08-08 09:40:23

BZOJ 1090 字符串折叠(区间DP)的相关文章

BZOJ 1090 字符串折叠(区间DP)

很明显的区间DP,设dp[l][r]表示[l,r]区间的字符串折叠后的最小长度. 可以通过两种方向转移,dp[l][r]=min(dp[l][i]+dp[i+1][r]). 另一种是折叠,dp[l][r]=min(dp[l][l+k-1]+cal((r-l+1)/k)+2).其中k是能整除(r-l+1)的数且区间能够折叠成k份,cal()函数计算数字的位数. 另外用了线段树维护hash值,可以每次验证logn. # include <cstdio> # include <cstring&

BZOJ 1090 字符串折叠(Hash + DP)

题目链接 字符串折叠 区间DP.f[l][r]为字符串在区间l到r的最小值 正常情况下 f[l][r] = min(f[l][r], f[l][l + k - 1] + f[l + k][r]); 当l到r以k为周期时 f[l][r] = min(f[l][r], 2 + sz(k) + f[l][l + (r - l + 1) / k - 1]); 判重的时候为了方便我用了哈希……当然其他方法应该也是可以的~ #include <bits/stdc++.h> using namespace

BZOJ 1090: [SCOI2003]字符串折叠( 区间dp )

按照题意dp...dp(l, r) = min{ dp(l, x) + dp(x+1, r) , 折叠(l, r) } 折叠(l, r)我是直接枚举长度然后哈希判.. -------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn = 109; con

BZOJ 1090 SCOI 2003 字符串折叠 区间DP

题目大意:给出一个字符串,在不改变这个字符串的内容的情况下可以将它进行折叠,具体见题里说的吧.问这个字符串最短可以折叠成多长. 思路:数据范围才100,怎么暴力怎么搞.首先是一个区间DP,设f[i][j]为字符串从i开始到j最短可以折叠成多短.要用到体中的折叠的方法,其实只需要暴力枚举这一段折叠成几段,然后用hash判定一下就行了. 当然不要忘了正常的区间DP. CODE: #include <cstdio> #include <cstring> #include <iost

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

1090: [SCOI2003]字符串折叠 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 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) =

BZOJ 1055 玩具取名(区间DP)

很显然的区间DP,定义dp[i][j][k], 如果dp[i][j][k]=1表示字符串[i,j]可以组成k字符. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map>

BZOJ 1068 [SCOI2007]压缩 区间DP

题意:链接 方法:区间DP 解析: MD写题解(吐槽)写到一半markdown挂了什么鬼! 要不要这样!你知道我的内心是什么样的吗! 吐槽,啊呸,写题解写到一半突然丢失了我的内心是崩溃的好吗! 来我们重新写题解(吐槽) 这道题我刚开始列了个瞎(和谐)动规(二维的裸区间) 加上乱七八糟的判断是否有M后,居然有交叉! 一定是我逻辑错误,对就是这样! 后来又是一顿瞎(和谐)搞之后,代码抽的爆炸,然后我一测,c-free挂掉- - 过了一个小时后,我选择死亡. 然后看了一眼hzw的题解. 看到那个三维之

HihoCOder1323 : 回文字符串(区间DP)

回文字符串 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个字符串 S ,最少需要几次增删改操作可以把 S 变成一个回文字符串? 一次操作可以在任意位置插入一个字符,或者删除任意一个字符,或者把任意一个字符修改成任意其他字符. 输入 字符串 S.S 的长度不超过100, 只包含'A'-'Z'. 输出 最少的修改次数. 样例输入 ABAD 样例输出 1 区间DP水题,见铺垫:密码脱落. #include<cstdio> #include<cstdlib

【bzoj2121】字符串游戏 区间dp

题目描述 给你一个字符串L和一个字符串集合S,如果S的某个子串在S集合中,那么可以将其删去,剩余的部分拼到一起成为新的L串.问:最后剩下的串长度的最小值. 输入 输入的第一行包含一个字符串,表示L. 第二行包含一个数字n,表示集合S中元素个数. 以下n行,每行一个字符串,表示S中的一个元素. 输入字符串都只包含小写字母. 输出 输出一个整数,表示L的最短长度. 样例输入 aaabccd3acabcaaa 样例输出 2 题解 我们考虑:每次删除连续的一段,对应到原串上即:删除 $[l,r]$ 中所