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\n",dfs(1,len));
return 0;
}

 

posted @ 2018-08-11 20:34  lmjer  阅读(108)  评论(0编辑  收藏  举报