bzoj1090: [SCOI2003]字符串折叠

区间dp。

用f[l][r]表示区间[l,r]最短能缩到多短。

然后状态转移方程有俩种

1.不折叠 f[l][r]=f[l][i]+f[i+1][r].   (l=<i<r)

2.折叠   f[l][r]=f[l][l+i-1]+2+(数字是几)  (1<=i<n)

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 200 + 10;

char s[maxn];
int f[maxn][maxn];

int h(int i,int n) {
    if(n/i<10) return 1;
    if(n/i<100) return 2;
    return 3;    
}

bool same(int l,int r,int k) {
    for(int i=k;i+k<=(r-l+1);i+=k) 
        for(int j=l;j<=(l+k-1);j++) 
            if(s[j]!=s[i+j]) return 0;    
    return 1;
}

int dp(int l,int r) {
    if(l==r) return 1;
    if(f[l][r]) return f[l][r];
    int &res=f[l][r];
    int n=res=r-l+1;
    for(int i=l;i<r;i++) res=min(res,dp(l,i)+dp(i+1,r));
    for(int i=1;i<n;i++) if(n%i==0) if(same(l,r,i)) res=min(res,dp(l,l+i-1)+2+h(i,n));
    return res;
}

int main() {
    scanf("%s",s+1);
    printf("%d\n",dp(1,strlen(s+1)));
    return 0;    
}
posted @ 2016-07-12 09:53  invoid  阅读(374)  评论(0编辑  收藏  举报