zoukankan      html  css  js  c++  java
  • bzoj1068[SCOI2007]压缩

    Description

      给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小
    写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没
    有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程

     

      另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。

    传送门

    Input

      输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。

    Output

      输出仅一行,即压缩后字符串的最短长度。

    Sample Input

    bcdcdcdcdxcdcdcdcd

    Sample Output

    12

    HINT

    在第一个例子中,解为aaaRa,在第二个例子中,解为bMcdRRxMcdRR。 

    【限制】 

    100%的数据满足:1<=n<=50 100%的数据满足:1<=n<=50

    题解

    这种题目区间dp比较明显。不过第一个例子在哪里……

    我们很容易就能想到记dp[i][j]为从i到j的最短压缩长度。但是中间的M使得它不好转移。因此我们再用一维。记dp[i][j][m]表示从i到j,中间是否有M的最短压缩长度。其中,m为0/1,m=0时中间没有M,否则有。最初时,dp[i][j][m]=j-i+1。当m=1时,我们可以得到

    dp[i][j][m]=dp[i][k][1]+dp[k+1][j][1]+1(i≤k<j)。

    其中的+1是因为需要第k位的后面需要插入一个M使得前面与后面不会互相干扰。

    因此对于任意的m,我们还可以只压缩前面那一段。因此有如下方程

    dp[i][j][m]=min(dp[i][j][m],dp[i][k][m]+j-k)(i≤k<j)

    当前后两段完全相同,并且中间均没有M的时候,我们可以把后面的一段替换为R。因此我们有

    dp[i][j][m]=min(dp[l][r][m],dp[l][(l+r)/2][0]+1)

    最后dp[0][n-1][1]即为答案

    代码

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 char ch[110];
     9 int dp[60][60][2];
    10 bool used[60][60][2];
    11 int len,ans;
    12 bool fold(int l,int r){
    13     int dis=r-l+1;
    14     if(dis&1)  return false;
    15     dis=dis/2;int i;
    16     for(i=l;i<=(l+r)/2;++i){
    17         if(ch[i]!=ch[i+dis])  return false;
    18     }
    19     return true;
    20 }
    21 int dfs(int l,int r,int m){
    22     int dis=r-l+1;
    23     if(dis==1)  return 1;
    24     if(used[l][r][m])  return dp[l][r][m];
    25     used[l][r][m]=1;
    26     int i,j;
    27     if(m){
    28         for(i=l;i<r;++i){
    29             dis=min(dis,dfs(l,i,1)+1+dfs(i+1,r,1));
    30         }
    31     }
    32     for(i=l;i<r;++i){
    33         dis=min(dis,dfs(l,i,m)+r-i);
    34     }
    35     if(fold(l,r)){
    36         dis=min(dis,dfs(l,(l+r)/2,0)+1);
    37     }
    38     dp[l][r][m]=dis;
    39     return dis;
    40 }
    41 int main(){
    42     scanf("%s",ch);
    43     len=strlen(ch);
    44     ans=dfs(0,len-1,1);
    45     printf("%d
    ",ans);
    46     return 0;
    47 }
  • 相关阅读:
    浅谈Java两种并发类型——计算密集型与IO密集型
    设置线程池的大小
    Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecuto
    gitlab的简单操作
    GitHub vs GitLab:区别?
    前端小知识汇总
    花里胡哨的CSS集锦
    码云如何上传代码
    小程序自定义底部导航
    Vue实践过程中的几个问题
  • 原文地址:https://www.cnblogs.com/lazytear/p/9191576.html
Copyright © 2011-2022 走看看