[CF825F] String Compression 题解

文章描述了一种方法,通过KMP算法确定字符串中的循环节,然后利用动态规划计算以每个位置为起点的子串压缩后的最小长度,以达到整体字符串的最小压缩长度。

题意

给定一个字符串 SSS,其中出现循环的子串压缩后长度为:循环节出现次数十进制下的位数+循环节长度,无循环的串也需要压缩。求压缩后的最小长度。

思路

对于串 TTT,对其执行 KMP 算法后得到 nxtnxtnxt 数组,可能的最小循环节长度 lenlenlen 即为 ∣T∣−nxt∣T∣|T|-nxt_{|T|}TnxtT,其中 ∣T∣|T|T 表示 TTT 的长度;如果 len∤∣T∣len\nmid |T|lenTTTT 中无小的循环节(即循环节长度为 ∣T∣|T|T)。对 SSS 串进行压缩可以认为是把 SSS 分成若干个子串,这些子串全部完全压缩。

考虑 dp。设 fif_ifi 表示将 SSS 串的前 iii 个字符进行压缩的最小长度。初始 fi=i+1f_i=i+1fi=i+1。转移方程即为:fi←min⁡{fj+cntj+1,i} (1≤j<i≤∣S∣)f_i\gets\min\{f_j+cnt_{j+1,i}\}\ (1\le j<i\le |S|)fimin{fj+cntj+1,i} (1j<iS),其中 cntx,ycnt_{x,y}cntx,y 表示将 SSS[x,y][x,y][x,y] 这个部分完全压缩后的长度,求法即为:对于每个 1≤i≤∣S∣1\le i\le |S|1iS,都将 SSS 的前 i−1i-1i1 个字符删除后跑 KMP,求得的 (j−i+1)−nxtj (i≤j≤∣S∣)(j-i+1)-nxt_j\ (i\le j\le |S|)(ji+1)nxtj (ijS) 即为 cnti,jcnt_i,jcnti,j,注意判断是否能够整除。时间复杂度 O(n2)O(n^2)O(n2)

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 8005;
char S[maxn]; int f[maxn],nxt[maxn];
int count(int x) { // 数出循环节十进制位数
    int res = 0;
    while (x) res ++, x /= 10;
    return res;
}
int n;
void KMP(char S[]) { // 求出的 nxt 数组下标从起点开始
    int len = strlen(S + 1);
    memset(nxt,0,sizeof(nxt)); 
    for (int i = 2,now = 0;i <= len;i ++) {
        while (now && S[i] != S[now + 1]) now = nxt[now];
        if (S[i] == S[now + 1]) now ++;
        nxt[i] = now;
    }
}
int main() {
    scanf("%s",S + 1); n = strlen(S + 1);
    for (int i = 1;i <= n;i ++)
        f[i] = i + 1;
    for (int i = 0;i <= n;i ++) {
        KMP(S + i); // 以每个 i 为开头跑出 nxt 数组
        for (int len = 1;i + len <= n;len ++) { // 枚举完全压缩的区间长度
            int j = i + len;
            if (len % (len - nxt[len]) == 0) // 存在循环节
                f[j] = min(f[j],f[i] + count(len / (len - nxt[len])) + len - nxt[len]);
            else f[j] = min(f[j],f[i] + len + 1); // 否则只能整个压缩
        }
    }
    printf("%d",f[n]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值