BZOJ 1090 字符串折叠(Hash + DP)

题目链接 字符串折叠

区间DP。$f[l][r]$为字符串在区间l到r的最小值

正常情况下 $f[l][r] = min(f[l][r], f[l][l+k-1]+f[l+k][r]);$

当$l$到$r$以$k$为周期时 $f[l][r] = min(f[l][r], 2+sz(k)+f[l][l+(r-l+1)/k-1]);$

判重的时候为了方便我用了哈希……当然其他方法应该也是可以的~

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef unsigned long long LL;

const int N = 210;
const int base = 233;

int f[N][N], n;
LL bin[N], Hash[N];
char s[N];

void Hashtable(){
	bin[0] = 1;
	rep(i, 1, n) bin[i] = bin[i - 1] * base;
	rep(i, 1, n) Hash[i] = Hash[i - 1] * base + s[i];
}

inline LL gethash(int l, int r){
	return Hash[r] - Hash[l - 1] * bin[r - l + 1];
}

inline int sz(int x){
	int ret = 0;
	for (; x;) ++ret, x /= 10;
	return ret;
}

inline bool judge(int l, int m, int r){
	if ((r - l + 1) % m) return 0;
	int t1 = (r - l + 1) / m;
	LL t = gethash(l, l + t1 - 1);
	for (int i = l; i <= r; i += t1)
		if (gethash(i, i + t1 - 1) != t) return 0;
	return 1;
}

int main(){

	scanf("%s", s + 1);
	n = strlen(s + 1);

	Hashtable();
	rep(i, 1, n){
		rep(j, 1, n){
			if (j - i + 1 <= n){
				int l = j, r = i + j - 1;
				f[l][r] = r - l + 1;
				rep(k, 1, i){
					f[l][r] = min(f[l][r], f[l][l + k - 1] + f[l + k][r]);
					if (judge(l, k, r)) f[l][r] = min(f[l][r], 2 + sz(k) + f[l][l + (r - l + 1) / k - 1]);
				}
			}
		}
	}

	printf("%d\n", f[1][n]);
	return 0;
}

 

posted @ 2017-08-01 22:57  cxhscst2  阅读(237)  评论(0编辑  收藏  举报