题意:
给一个字符串,可以把连续相同的部分进行缩写成k(S)的形式,S是一个字符串,k表示有连续相同的S
例如,abgogogogo,可以缩写成ab4(go). 还可以嵌套缩写,比如
“nowletsgogogoletsgogogo”, 缩写成“now2(lets3(go))”,求出最小的长度。
思路:想了好久,开始以为是KMP或者后缀数组的。结果是个区间DP。定义dp[i][j]表示i到j所形成的最小的长度,转移方程为:dp[i][j] = min(dp[i][k], dp[k+1][j]) i <= k < j,因为字符串可以缩写,所以对于【i,j】判断是否可以缩写,即是否可以m个相同的片段(假设长度为L),如果可以dp[i][j] = min(dp[i][j], cal(L)+dp[i][i+L-1]+2).
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 205
char w[N];
int dp[N][N];
int cal(int a) {
int re = 0;
while (a) re++, a/=10;
return re;
}
bool ch(int l, int r, int k) {
int i, j;
for (i = l;i < l+k;i++) {
for (j = k;i+j<=r;j+=k) {
if (w[i] != w[i+j]) return true;
}
}
return false;
}
int main() {
int T, k, i, j, len;
scanf("%d", &T);
while (T--) {
scanf("%s", w);
len = strlen(w);
memset(dp, 0x3f, sizeof(dp));
for (i = 0;i < len;i++) dp[i][i] = 1;
for (k = 2;k <= len;k++) {
for (i = 0;i <= len-k;i++) {
int r = i+k-1;
for (j = i;j < r;j++) {
dp[i][r] = min(dp[i][r], dp[i][j]+dp[j+1][r]);
}
for (j = 1;j <= k/2;j++) {
if (k%j) continue;
if (ch(i, r, j)) continue;
dp[i][r] = min(dp[i][r], dp[i][i+j-1]+cal(k/j)+2);
}
}
}
printf("%d\n", dp[0][len-1]);
}
}