首页 > 其他分享 >CF825F String Compression题解

CF825F String Compression题解

时间:2024-07-16 21:22:43浏览次数:14  
标签:nxt String int 题解 len CF825F 字符串 8010

思路

容易想到是个动态规划。首先设 \(f_i\) 表示字符串前 \(i\) 个字符所组成的字符串的答案。状态定义好了,接下来就是考虑如何转移了。因为由 \(f_i\) 可以得到所有 \(f_j\),其中 \(i+j\le len\),转移方程为 \(f_i=f_j+x\),其中 \(x\) 为 字符串 \(i+1\) 至 \(j\) 的最优压缩。

接下来只要把如何求最优压缩解决了这道题就做出来了。考虑暴力求解,随便选择一个前缀 \(T\) 遍历整个字符串,看 \(T\) 是否是原字符串的循环串。如何优化呢?我们要做的事情就是找一个最长前缀 \(T\),使得字符串 \(T\) 是原字符串的循环串。有没有感觉似曾相识?对了,就是对字符串求一遍 KMPborder 数组。

所以转移方程就出来了 $f_{i + k} = \min(f_{i + k}, f_i + (k - nxt_k) + sum) $。

这道题也就做出来了,具体参见代码。

代码

#include <bits/stdc++.h>
using namespace std;
int f[100010];
int nxt[8010];
char s[8010], t[8010];
void kmp(char t[])
{
    memset(nxt, 0, sizeof(nxt));
    int j = 0;
    nxt[1] = 0, nxt[0] = 0;
    int len = strlen(t + 1);
    for (int i = 2; i <= len; i++)
    {
        while (j && t[i] != t[j + 1])
            j = nxt[j];
        if (t[i] == t[j + 1])
            j++;
        nxt[i] = j;
    }
}
int main()
{
    cin >> s + 1;
    int len = strlen(s + 1);
    for (int i = 1; i <= len; i++)
        f[i] = i + 1;
    for (int i = 0; i < len; i++)
    {
        memset(t, 0, sizeof(t));
        int ss = 0;
        for (int j = i + 1; j <= len; j++)
        {
            t[++ss] = s[j];
        }
        kmp(t);
        for (int k = 1; k + i <= len; k++)
        {
            if (k % (k - nxt[k]) == 0)
            {
                int cnt = k / (k - nxt[k]), sum = 0;
                while (cnt)
                    sum++, cnt /= 10;
                f[i + k] = min(f[i + k], f[i] + (k - nxt[k]) + sum);
            }
            else
                f[i + k] = min(f[i + k], f[i] + 1 + k);
        }
    }
    cout << f[len];
    return 0;
}

标签:nxt,String,int,题解,len,CF825F,字符串,8010
From: https://www.cnblogs.com/merlinkkk/p/18306124

相关文章

  • [ABC347E] Set Add Query题解
    思路通过读题发现,每个数变化当且仅当这个数在集合内。所以不妨设它被添加进来的时间点为\(L_i\),它被删除的时间点为\(R_i\),所以它被增加的数量就是这段时间内集合数量之和。所以用一个变量\(cnt\)模拟当前集合内有多少个数,前缀和维护即可。具体实现参见代码。代码#include<......
  • CF1898D Absolute Beauty 题解
    思路容易发现,如果\(a_i>b_i\)则将\(a_i\)和\(b_i\)交换。在数轴上标出要交换的四个数的位置若线段\(a_ib_i\)和线段\(a_jb_j\)互不相交,此时交换比两条线段处于其他位置时更优。具体证明这里就不再赘述,其他题解讲的已经很清楚了。所以只需交换最大的\(a_i\)和最小......
  • [ABC338E] Chords 题解
    思路思路还是很显然的,简单总结一下思路:首先,将圆环从点\(1\)到\(2N\)切开,并将其拉直成一条直线。在切开状态下,原来的弦变成了直线上的曲线。我们需要判断这些曲线之间是否存在交点。在切开状态下,曲线之间的交点等价于满足\(A_i<A_j<B_i<B_j\)的不同曲线\(i\)和......
  • [ABC258Ex] Odd Steps 题解
    思路拿到这道题,第一时间肯定想到是\(dp\)题目。朴素DP用\(dp_i\)表示序列和为\(i\)的序列个数。因为原数组由奇数组成,所以\(dp\)只可能由\(dp_{i-1}\),\(dp_{i-3}\)等等转移过来,若\(i\inA\),\(dp_i=0\)。即:\[dp_i=\begin{cases}0&i\inA\\dp_{i-1}+dp_{i-3}+\c......
  • CF1859A题解
    CF1859A题解思路考虑一种极端情况,\(b\)数组内的数全部比\(a\)大,这样也无法整除,所以这就是这道题的突破口。我们让\(b\)数组内的数全部比\(a\)里的大,最方便的实现方法就是把原数组内的最大的数放进\(b\)数组,剩下的放进\(a\)数组。注意特判无解情况:原数组内的数一样,这......
  • [ABC352D]题解
    题意在长为\(n\)的序列\(a\)中找出\(k\)个数,设它们的下表为$p_1\(,\)p_2$到\(p_k\),满足这\(k\)个数从小到大排列过后是一个公差为\(1\)的等差数列。求满足条件的\(k\)个数的最大的\(p\)减去最小的\(p\)最小。输出这个值。思路把数组\(a\)排一遍序,滑动窗......
  • [ABC352E]题解
    思路这里提供一种暴力做法。方法就是当边数到达一个值过后就不加边了。我取的值是\(500000\),实际上可以开大一些,只要\(x\logx\)不超时就行了。代码赛时提交记录#include<bits/stdc++.h>usingnamespacestd;#defineintlonglonginta[200020];intcnt;structrec......
  • P10378 [GESP202403 七级] 交流问题题解
    思路我们把关系想成一张图,每次输入就给两个人连一条边。因为一个人只有两种选择,所以我们在一个联通块内随便找一个点,跑一遍搜索,找出这个联通块内的答案。代码如下。voiddfs(intu,intcolor){cnt2++;//cnt2是这个连通块内的总点数cnt1+=color;//这个是一所学校内......
  • 【题解】金明的预算方案
    原题传送门题目描述金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过\(n\)元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附......
  • P5537 题解
    blog。今天在XDFZ听ljy讲的串串(?)题,瞎写写就混了个最优解,来发个题解(注意到树的形态不变,所以可以记录兄弟间的编号rank。每个点就可以表示为若干rank构成的路径,例如下图:然后将每个点的这个路径压成hash,记为\(H_i\),并丢进map里。假设从\(x\)开始,可以完全遍历完\(a_......