1068. [SCOI2007]压缩【区间DP】

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

 

艹二维做法艹了好久,竟然还过样例了还有60(惊)
果然还是数据太水了
正解的三维做法非常巧妙
dp[x][y][1\0]表示[x,y]区间内是否有M。默认x-1前面跟着一个M
枚举断点k
dp[x][y][1]就可以从k划分的两个区间的0\1状态转移了。毕竟中间有M了可以为所欲为(雾)
dp[x][y][0]就只能从0的转移过来了。注意如果[x,y]可以从中间一分为二相同的话,还要加一个状态转移

 

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 char a[150];
 6 int dp[150][150][2],n;
 7 int check(int x,int y)
 8 {
 9     int mid=(x+y)/2;
10     for (int i=0;i<mid-x+1;++i)
11         if (a[x+i] != a[mid+i+1])
12             return 0;
13     return 1;
14 }
15 
16 int main()
17 {
18     scanf("%s",a+1);
19     n=strlen(a+1);
20     memset(dp,0x3f,sizeof(dp));
21     for (int i=1; i<=n; ++i)
22     {
23         for (int j=1; j<=n-i+1; ++j)
24         {
25             int x=j,y=j+i-1;
26             dp[x][y][0]=dp[x][y][1]=y-x+1;
27             for (int k=x; k<y; ++k)
28             {
29                 dp[x][y][1]=min(dp[x][y][1],min(dp[x][k][0],dp[x][k][1])+1+min(dp[k+1][y][0],dp[k+1][y][1]));
30                 dp[x][y][0]=min(dp[x][y][0],dp[x][k][0]+y-k);
31                 if ((y-x+1)%2==0 && check(x,y)) dp[x][y][0]=min(dp[x][y][0],dp[x][(x+y)/2][0]+1);
32             }
33 
34         }
35     }
36     printf("%d",min(dp[1][n][0],dp[1][n][1]));
37 }

 

posted @ 2018-03-31 08:12  Refun  阅读(157)  评论(0编辑  收藏  举报