首页 > 代码库 > BZOJ 1090 字符串折叠(Hash + DP)

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

 

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