[BZOJ1090][SCOI2003]字符串折叠

[BZOJ1090][SCOI2003]字符串折叠

试题描述

折叠的定义如下:

  1. 一个字符串可以看成它自身的折叠。记作 (S Rightarrow S)

  2. (X(S))(X(X>1))(S) 连接在一起的串的折叠。记作 (X(S) Rightarrow SSSS…S(X个S))

  3. 如果 (A Rightarrow A’, B Rightarrow B’),则 (AB Rightarrow A’B’) 例如,因为 (3(A) Rightarrow AAA, 2(B) Rightarrow BB),所以 (3(A)C2(B) Rightarrow AAACBB),而 (2(3(A)C)2(B) Rightarrow AAACAAACBB)

给一个字符串,求它的最短折叠。例如 (AAAAAAAAAABABABCCD) 的最短折叠为:(9(A)3(AB)CCD)

输入

仅一行,即字符串 (S),长度保证不超过 (100)

输出

仅一行,即最短的折叠长度。

输入示例

NEERCYESYESYESNEERCYESYESYES

输出示例

14

数据规模及约定

见“输入

题解

(f(l, r)) 表示对于区间 ([l, r]) 内的字符串最短能压缩成的长度。那么两种转移:第一种,拼接,即 (f(l, r) = min{f(l, k) + f(k + 1, r) | k in [l, r)});第二种,对于周期串,枚举折叠几倍。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

#define maxn 110

int n, f[maxn][maxn], fa[maxn];
char str[maxn];

int cntdig(int x) {
	int cnt = 0;
	while(x) cnt++, x /= 10;
	return cnt;
}

int main() {
	scanf("%s", str + 1);
	n = strlen(str + 1);
	
	rep(i, 1, n) rep(j, i, n) f[i][j] = j - i + 1;
	rep(len, 1, n) rep(l, 1, n - len + 1) {
		int r = l + len - 1;
		rep(i, l, r - 1) f[l][r] = min(f[l][r], f[l][i] + f[i+1][r]);
		fa[1] = fa[2] = 1;
		rep(i, 2, r - l + 1) {
			int j = fa[i];
			while(j > 1 && str[i+l-1] != str[j+l-1]) j = fa[j];
			fa[i+1] = str[i+l-1] == str[j+l-1] ? j + 1 : 1;
		}
		if(fa[r-l+2] < (r - l + 1 >> 1) + 1) continue;
//		printf("[%d, %d]
", l, r);
//		rep(i, 1, r - l + 2) printf("%d%s", fa[i], i < r - l + 2 ? "->" : "
");
		int tlen = r - l + 2 - fa[r-l+2], ini = tlen;
		for(; ini < r - l + 1; ini += tlen) if((r - l + 1) % ini == 0)
			f[l][r] = min(f[l][r], f[r-ini+1][r] + cntdig((r - l + 1) / ini) + 2);
//		printf("f[%d][%d] = %d
", l, r, f[l][r]);
	}
	
	printf("%d
", f[1][n]);
	
	return 0;
}

总感觉在哪做过这道题。

原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7736275.html