bzoj1090(区间dp)

Posted lmjer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1090(区间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))

读了半天才懂题目,原来求最短折叠长度是求2(NEERC3(YES))这个字符串的长

那么就很简单了

一个区间dp模型

dp[l][r]=min(dp[l][r],dp[l][i]+dp[i+1][r])

当s[l...i]为s[i+1...r]子串时就dp[l][r]=min(dp[l][r],dp[l][k]+2+calc((r-l+1)/(k-l+1)))

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=200;
char S[maxn],s[maxn];
int dp[maxn][maxn];
bool mark[maxn][maxn];

bool judge(int l,int r,int cl,int cr){
     if((cr-cl+1)%(r-l+1)) return false;
     //printf("%d ",cl+i);
     if(s[cl]!=s[l]) return false;
     for (int i=1;i<=cr-cl;i++){
        if(s[cl+i]!=s[l+i%(r-l+1)]) return false;
     }
    return true;
}

int calc(int x){
    int num=0;
    while(x){
        num++;
        x/=10;
    }
    return num;
}

int dfs(int l,int r){
     if(l==r) return 1;
     if(mark[l][r]) return dp[l][r];
     mark[l][r]=1;
     int t=(r-l+1);
     for (int i=l;i<r;i++){
        t=min(t,dfs(l,i)+dfs(i+1,r));
        if(judge(l,i,i+1,r)){
           t=min(t,dfs(l,i)+2+calc((r-i)/(i-l+1)+1));
        }
     }
    return dp[l][r]=t;
}

int main(){
    int len;
    scanf("%s",S);
    len=strlen(S);
    for (int i=0;i<len;i++) s[i+1]=S[i];
    //printf("%d",len);
    printf("%d
",dfs(1,len));
return 0;
}

 

以上是关于bzoj1090(区间dp)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

bzoj1090(区间dp)

bzoj1090题解

BZOJ1090: [SCOI2003]字符串折叠

bzoj1090:[SCOI2003]字符串折叠