题目大意:给出一个字符串,在不改变这个字符串的内容的情况下可以将它进行折叠,具体见题里说的吧。问这个字符串最短可以折叠成多长。
思路:数据范围才100,怎么暴力怎么搞。首先是一个区间DP,设f[i][j]为字符串从i开始到j最短可以折叠成多短。要用到体中的折叠的方法,其实只需要暴力枚举这一段折叠成几段,然后用hash判定一下就行了。
当然不要忘了正常的区间DP。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 110 #define BASE 23333 #define INF 0x3f3f3f3f using namespace std; char s[MAX]; unsigned long long hash[MAX],power[MAX]; int table[MAX]; int f[MAX][MAX]; void Pretreatment() { for(int i = 1; i <= 9; ++i) table[i] = 1; for(int i = 10; i <= 99; ++i) table[i] = 2; table[100] = 3; power[0] = 1; for(int i = 1; i < MAX; ++i) power[i] = power[i - 1] * BASE; } inline unsigned long long GetHash(int l,int r) { return hash[r] - hash[l - 1] * power[r - l + 1]; } inline int Divide(int l,int r,int p) { if((r - l + 1) % p) return INF; int len = (r - l + 1) / p; unsigned long long base = GetHash(l,l + len - 1); for(int i = l; i <= r; i += len) if(GetHash(i,i + len - 1) != base) return INF; return table[p] + 2 + f[l][l + len - 1]; } int main() { Pretreatment(); scanf("%s",s + 1); int length = strlen(s + 1); for(int i = 1; i <= length; ++i) hash[i] = hash[i - 1] * BASE + s[i]; for(int i = 1; i <= length; ++i) for(int j = i; j <= length; ++j) f[i][j] = j - i + 1; for(int j = 1; j <= length; ++j) for(int i = 1; i + j - 1 <= length; ++i) { for(int k = 1; k <= j; ++k) f[i][i + j - 1] = min(f[i][i + j - 1],Divide(i,i + j - 1,k)); for(int k = 1; k < j; ++k) f[i][i + j - 1] = min(f[i][i + j - 1],f[i][i + k - 1] + f[i + k][i + j - 1]); } cout << f[1][length] << endl; return 0; }
BZOJ 1090 SCOI 2003 字符串折叠 区间DP
原文地址:http://blog.csdn.net/jiangyuze831/article/details/42706433