SCOI2003 字符串折叠

题目传送门

(DP)的实现也要下一下功夫,比如这题,知道转移方程却不会实现


定义f[i][j]为区间([i,j])折叠的最短长度
然后就是区间(DP)的套路,枚举中间断点,然后转移

如何判断能否折叠,以及折叠后的处理没有想到
还要多加练习

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
      k = k * 10 + c - 48, c = getchar();
    return k * f;
}
int f[110][110]; char s[110];
bool cmp(int x, int k, int y) { //判断能否折叠
    if(((y-x+1) % (k-x+1))) return false;
    int pos = x;
    for(int i = x; i <= y; ++i) {
        if(s[i] != s[pos++]) return false;
        if(pos > k) pos = x;
    }
    return true;
}
int calc(int x) { //折叠后的数字不一定只为个位数,要计算它的位数
    int num = 0;
    while(x) ++num, x /= 10;
    return num;
}
int main() {
    scanf("%s", s+1); int len = strlen(s+1);
    memset(f, 127/3, sizeof(f));
    for(int l = 0; l <= len; ++l)
        for(int i = 1; i <= len-l+1; ++i) {
            int j = i + l - 1; f[i][j] = l;
            for(int k = i; k < j; ++k) {
                if(!cmp(i, k, j)) f[i][j] = min(f[i][j], f[i][k] + f[k+1][j]);
                else f[i][j] = min(f[i][j], f[i][k] + 2 + calc(l/(k-i+1)));
            }
        }
    cout << f[1][len];
    return 0;
}
原文地址:https://www.cnblogs.com/morslin/p/11855424.html