题目链接:BZOJ - 1068
题目分析
这种记忆化搜索(区间 DP) 之前就做过类似的,也是字符串压缩问题,不过这道题稍微复杂一些。
需要注意如果某一段是 S1S1 重复,那么可以变成 M + Solve(S1) + R ,不过这个 Solve(S1) 中不能在中间有 M ,否则后面的 R 向前找到的 M 就不再是开头的 M 了。
代码
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std; const int MaxL = 50 + 5; int l, Ans; int g[MaxL][MaxL][3]; char S[MaxL]; bool Check(int l, int r) { if ((r - l + 1) & 1) return false; int mid = (l + r) >> 1, t = (r - l + 1) >> 1; for (int i = l; i <= mid; ++i) if (S[i] != S[i + t]) return false; return true; } int Solve(int l, int r, int f) { if (g[l][r][f] > 0) return g[l][r][f]; int ret = r - l + 1, t; if (Check(l, r)) { t = Solve(l, l + ((r - l) / 2), 2); ++t; //R if (f == 0) ++t; //M if (ret > t) ret = t; } for (int i = l; i <= r - 1; ++i) { if (f != 2) t = Solve(l, i, f) + Solve(i + 1, r, 0); else t = Solve(l, i, 2) + (r - i); if (ret > t) ret = t; } g[l][r][f] = ret; return ret; } int main() { scanf("%s", S + 1); l = strlen(S + 1); Ans = Solve(1, l, 1); printf("%d ", Ans); return 0; }