题意
折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) SSSS…S(X个S)。 3. 如果A A’, BB’,则AB A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B) AAACBB,而2(3(A)C)2(B)AAACAAACBB 给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。字符串长度不超过100
看到scoi和字符串同时出现我就放心了
然而这道题是dp水题。f[l][r]表示s[l...r]折叠的最短长度。转移见代码。
#include<set>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline int read() {
int x = 0, flag = 1; char ch = getchar();
while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }
while (ch <= '9' && ch >= '0') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * flag;
}
#define rep(ii, aa, bb) for (int ii = aa; ii <= bb; ii++)
#define drp(ii, aa, bb) for (int ii = aa; ii >= bb; ii--)
#define N 101
#define ll long long
#define ha 1000000007
int f[N][N];
char s[N];
bool check(int l, int k, int r) { //检查s[l...r]是否可以由s[l...k]重复得到
if ((r - l + 1) % (k - l + 1) != 0) return 0;
rep(i, l, r) if (s[i] != s[(i - l) % (k - l + 1) + l]) return 0;
return 1;
}
int calc(int x) { //计算十进制数x有多少位
int cnt = 0;
while (x) x /= 10, cnt++;
return cnt;
}
int dp(int l, int r) {
if (f[l][r] != -1) return f[l][r];
if (l == r) return f[l][r] = 1;
f[l][r] = r - l + 1;
rep(k, l, r - 1) {
f[l][r] = min(f[l][r], dp(l, k) + dp(k + 1, r));
if (check(l, k, r)) f[l][r] = min(f[l][r], dp(l, k) + 2 + calc((r - k) / (k - l + 1) + 1)); //注意这里要写对,我就是写错了wa了四次
}
return f[l][r];
}
int main() {
cin >> s + 1;
rep(i, 0, 100) rep(j, 0, 100) f[i][j] = -1;
cout << dp(1, strlen(s + 1));
return 0;
}