# [Luogu P2470] [BZOJ 1068] [SCOI2007]压缩

### 题目描述

bcdcdcdcd可以压缩为bMcdRR，下面是解压缩的过程：

b b b
bM b .
bMc bc c
bMcd bcd cd
bMcdR bcdcd cdcd
bMcdRR bcdcdcdcd cdcdcdcd

### 输入输出样例

#### 输入样例#1：

aaaaaaa


#### 输出样例#1：

5


#### 输入样例#2：

bcdcdcdcdxcdcdcdcd


#### 输出样例#2：

12


### 说明

【限制】

50%的数据满足：$1\le n\le 20$

100%的数据满足：$1\le n\le 50$

### 解题分析

$dp[i]$表示长度为$i$的前缀的最短长度， 每次我们考虑向后添加一段形如M***R**的段， 然后转移。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <climits>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define BASE 233
#define MOD 998244353
#define MX 55
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int len;
int dp[MX], hs[MX], base[MX];
char str[MX];
IN int seg(R int l, R int r) {return (hs[r] - 1ll * hs[l - 1] * base[r - l + 1] % MOD + MOD) % MOD;}
struct INFO {bool typ; int ret;};
IN INFO get(R int l, R int r)
{
int best = INT_MAX, sym = 1, avai = r - l + 1, mid;
W (l < r)
{
mid = l + r >> 1;
W (l < r && seg(l, mid) != seg(mid + 1, r)) --r, mid = l + r >> 1, ++sym;
if (l == r) break;
++sym, r = mid;
best = min(best, sym + r - l + 1);
}
return (best <= avai ? (INFO){false, best} : (INFO){true, avai});
}
int main(void)
{
scanf("%s", str + 1);
len = std::strlen(str + 1);
base[0] = 1;
for (R int i = 1; i <= len; ++i)
{
base[i] = 1ll * base[i - 1] * BASE % MOD;
hs[i] = (1ll * BASE * hs[i - 1] % MOD + str[i]) % MOD;
}
INFO res;
for (R int i = 1; i <= len; ++i)
{
res = get(1, i);
if (!res.typ) dp[i] = res.ret - 1;
else dp[i] = res.ret;
for (R int j = 2; j <= i; ++j)
{
res = get(j, i);
dp[i] = min(dp[i], dp[j - 1] + res.ret);
}
}
printf("%d\n", dp[len]);
}



©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客