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

P4302 [SCOI2003]字符串折叠

题目描述

折叠的定义如下:

  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。

输入输出格式

输入格式:

仅一行,即字符串S,长度保证不超过100。

输出格式:

仅一行,即最短的折叠长度。

输入输出样例

输入样例#1:

NEERCYESYESYESNEERCYESYESYES

输出样例#1:

14

说明

一个最短的折叠为:2(NEERC3(YES))

考试的题目,还不会区间dp,什么都不知道,考试的时候思路大概想到了,但是没有想到怎么实现。
用\(F[i][j]\)表示从第\(i\)个字符到第\(j\)个字符的最小长度。枚举中间断点,一定要先处理完中间才能处理两边考试的时候就是不晓得怎么枚举(我还是太菜了)。
还有一点很容易错的,字符折叠起来前面的数字可能为不止占一位(如AAAAAAAAAA ---> 10(A))。
难点在于怎样判断折叠,看到网上很多大佬用%什么的很麻烦,其实我们只要算出折叠完后字母部分有多长,然后用当前位置减去长度就可以了。因为既然可以枚举到这里,那么前面一定保证了相同,这是我们没必要一定搞到第一个的位置去判断。具体看代码吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int len;
int f[110][110];
int dp[110];
char ch[110];
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;
    for(int i=x2;i<=y2;i++)
    {
        if(ch[i]!=ch[i-len])
        return false;
    }
    return true;
}
int cal(int k)
{
    int qwe=0;
    while(k)
    {
        qwe++;
        k/=10;
    }
    return qwe;
}
int main()
{
    //freopen("char.in","r",stdin);
    //freopen("char.out","w",stdout);
    memset(f,0x3f,sizeof(f));
    cin>>ch;
    len=strlen(ch);
    for(int i=0;i<len;i++)f[i][i]=1;
    for(int l=1;l<len;l++)
    {
        for(int i=0;i<len-l;i++)
        {
            int j=i+l;
            f[i][j]=(j-i+1);
            for(int k=i;k<j;k++)
            {
                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("f[%d][%d]=%d\n",i,j,f[i][j]);
            }
        }
    }
    cout<<f[0][len-1];
    return 0;
}

原文地址:https://www.cnblogs.com/lsgjcya/p/9105367.html

时间: 2024-10-08 22:10:41

[SCOI2003]字符串折叠(区间dp)的相关文章

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】字符串折叠 区间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 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 SCOI 2003 字符串折叠 区间DP

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

【BZOJ】1090: [SCOI2003]字符串折叠(dp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1090 随便yy一下.. 设f[i,j]表示i-j的最小长度 f[i, j]=min{j-i+1, f[i,k]+f[k+1, j], count[x]+2+f[i, i+x-1]},其中count[x]表示x的位数,最后边的转移那个条件是i~j都是长度为x的串连在一起. 然后最后那个转移暴力233可以水过... #include <cstdio> #include <cstring>

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

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1090 [题意] 给定一个字符串,问将字符串折叠后的最小长度. [思路] 设f[i][j]表示将区间ij折叠后的最小长度,则有转移式: f[i][j]=min{ j-i+1,f[i][k]+f[k+1][j],f[i][i+x-1]+2+digit((j-i+1)/x) } 第一项代表不折叠,第二项代表当前不折叠,第三项代表以x长度折叠ij区间,条件是满足ij区间以x为循环节. [代码

P4302 [SCOI2003]字符串折叠

题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作S = S X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) = SSSS…S(X个S). 如果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. 输入输出格式

BZOJ 1090 SCOI2003 字符串折叠 动态规划+Hash

题目大意:给定一个字符串,求按照题中所给的压缩方式最短能压缩到多长 区间DP 令f[i][j]表示[i,j]区间内的字符串最短能压缩到多长 普通的区间DP:f[i][j]=min{f[i][k]+f[k+1][j]} (i<=k<=j-1) 此外如果对这段字符串进行压缩,那么我们可以枚举循环节,用Hash来判断 如果k是一个循环节,那么有f[i][j]=min(f[i][j],f[i][i+k-1]+digit[len/k]+2) 其中len=j-i+1,digit表示一个数在十进制下的长度

bzoj1090:[SCOI2003]字符串折叠

思路:区间dp,令f[l][r]表示l到r的答案,于是f[l][r]=min(f[l][mid],f[mid+1][r]),如果能折叠f[l][r]=min(f[l][r],f[l][l+len-1]+calc(r-l+1,len),calc是计算数字的长度.记忆化搜索即可. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include