比赛 |
EYOI与SBOI开学欢乐赛13th |
评测结果 |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
题目名称 |
折叠字符串(Folding) |
最终得分 |
100 |
用户昵称 |
lihaoze |
运行时间 |
0.000 s |
代码语言 |
C++ |
内存使用 |
0.00 MiB |
提交时间 |
2022-10-21 20:57:20 |
显示代码纯文本
#include <bits/stdc++.h>
const int N = 110;
int f[N][N], p[N][N], n; // f[i, j]: s[i, j] 折叠后长度(包括括号数字),p[i, j]: 断点以及子串构成信息
char s[N];
bool eq(int r, int ed, int len) {
for (int i = 0; i < len; ++ i)
if (s[ed - i] != s[r - i]) return false;
return true;
}
void print(int l, int r) {
if (p[l][r] == 0) {
for (int i = l; i <= r; ++ i)
std::cout << s[i];
} else if (p[l][r] > 0) {
print(l, p[l][r]), print(p[l][r] + 1, r);
} else {
int len = -p[l][r];
std::cout << (r - l + 1) / len << '(';
print(l, l + len - 1);
std::cout << ')';
}
}
int main() {
freopen("folding.in", "r", stdin);
freopen("folding.out", "w", stdout);
std::cin >> s + 1, n = strlen(s + 1);
memset(f, 0x3f, sizeof f);
for (int len = 1; len <= n; ++ len)
for (int l = 1; l <= n - len + 1; ++ l) {
int r = l + len - 1;
if (len == 1) f[l][r] = 1;
// 维护最小值
else for (int k = l; k < r; ++ k)
if (f[l][k] + f[k + 1][r] < f[l][r])
f[l][r] = f[l][k] + f[k + 1][r],
p[l][r] = k;
// 合并相同子串
for (int ed = r + len, cnt = 2; ed <= n && eq(r, ed, len); ed += len, ++ cnt)
if (f[l][r] + 2 + std::to_string(cnt).length() < f[l][ed])
f[l][ed] = f[l][r] + 2 + std::to_string(cnt).length(),
p[l][ed] = -len; // -: 子串由len长子串构成
}
print(1, n);
return 0;
}