BZOJ 1090 SCOI 2003 字符串折叠 区间DP

来源:互联网 发布:node服务器环境 编辑:程序博客网 时间:2024/06/04 12:05

题目大意:给出一个字符串,在不改变这个字符串的内容的情况下可以将它进行折叠,具体见题里说的吧。问这个字符串最短可以折叠成多长。


思路:数据范围才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 0x3f3f3f3fusing 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;}


0 0