比赛 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;
}