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

折叠的定义如下: 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))

dp{i,j}表示从ij最小的字符串长度。
状态转移方程为dp{l,r}=min{r-l+1,dp{l,k}+dp{k+1,r}}/l<=k<r
还要考虑字符串是否可以折叠,若可以折叠
dp{l,r}=min(dp{l,r},dp{l,k}+2+cal((r-l+1)/(k-l+1))}.
public class _1090 {
    static String s;
    static int[][] f;
    static boolean[][] vis;
    public static boolean repeat(int l,int r,int li,int ri){ //看有没有折叠部分
        int bi=r-l+1;
        int si=ri-li+1;
        if(bi%si!=0){
            return false;
        }
        for(int i=l;i<=r;++i){
            if(s.charAt(i)!=s.charAt((i-l)%si+li)){
                return false;
            }
        }
        return true;
    }
    public static int cal(int a,int b){ //处理10以上折叠部分的数
        return String.valueOf(a/b).length();
    }
    public static int dp(int l,int r){
        if(l==r){
            return 1;
        }
        if(vis[l][r]){ //记忆化搜索
            return f[l][r]; 
        }
        vis[l][r]=true;
        int t=r-l+1; //当前的长度
        for(int k=l;k<r;++k){
            int ld=dp(l,k);
            int rd=dp(k+1,r);
            t=Math.min(t,ld+rd);
            if(repeat(k+1,r,l,k)){ //判断可否折叠
                t=Math.min(t,ld+2+cal(r-l+1,k-l+1));
            }
        }
        return f[l][r]=t;
    }

    public static void main(String[] args){
        Scanner cin=new Scanner(System.in);
        s=cin.next();
        vis=new boolean[s.length()][s.length()];
        f=new int[s.length()][s.length()];
        System.out.println(dp(0,s.length()-1));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值