1 条题解

  • 0
    @ 2025-5-19 21:35:16

    题目分析​

    本题要求将一个由大写字母 'A' 到 'Z' 组成的序列,折叠成字符数最少的折叠序列。题目定义了三种折叠规则: ​ 单个字符:单个大写字母本身就是一种简单的折叠序列,展开后为其自身,这是折叠序列的最基本形式。​ 连接操作:若有两个折叠序列 S 和 Q,将它们连接起来形成的 SQ 也是折叠序列,其展开结果为 S 和 Q 各自展开后的连接,这使得可以将多个部分的折叠结果组合起来。​

    重复操作

    当 S 是折叠序列,X 是大于 1 的整数时,X (S) 构成折叠序列,展开后是 S 重复 X 次,这是实现对重复子序列压缩折叠的关键操作 。​

    解题思路​

    暴力枚举所有可能的子序列:通过两层循环遍历字符串,确定所有可能的子序列范围。外层循环控制子序列的起始位置,内层循环控制子序列的结束位置。对于每个确定的子序列,检查它在整个字符串中重复出现的次数。​

    判断子序列是否重复出现:在确定子序列后,从字符串开头开始,每次以子序列的长度为步长,检查后续相同长度的子串是否与该子序列相等。若连续出现多次相同子序列,则记录其重复次数。​

    计算折叠后的长度:对于每个找到的重复子序列,计算将其折叠后的长度,即重复次数的数字位数加上子序列本身长度加上括号的长度(2)。同时计算不折叠时的长度,即子序列重复出现的总长度。比较折叠前后的长度,若折叠后长度更短,则使用折叠后的表示替换原字符串中的重复子序列部分。​

    处理非重复子序列:对于未找到重复的子序列,即单个字符或不重复的子串,保持其原样。 ​ 迭代优化:对字符串进行多次上述操作,因为一次折叠后可能会产生新的可折叠子序列。直到无法再找到可以进一步折叠以缩短字符串长度的子序列为止,此时得到的字符串即为最短的折叠序列。​

    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,nd[105],f[105][105],pre[105][105],nxt[105][105];
    char s[105];
    void print(int L,int R)
    {
        if(L==R) putchar(s[L]);
        else if(pre[L][R]>0)
        {
            print(L,pre[L][R]);
            print(pre[L][R]+1,R);
        }
        else
        {
            printf("%d(",-(R-L+1)/pre[L][R]);
            print(L,L-pre[L][R]-1);
            putchar(')');
        }
    }
    int main()
    {
        #ifdef local
        freopen("pro.in","r",stdin);
        #endif
        for(int i=2;i<=9;i++) nd[i]=1;
        for(int i=10;i<=99;i++) nd[i]=2;
        nd[100]=3;
        scanf("%s",s+1); n=strlen(s+1);
        memset(f,0x3f,sizeof(f));
        for(int i=1;i<=n;i++) f[i][i]=1;
        for(int bg=1;bg<=n;bg++)
        {
            nxt[bg][0]=0;
            for(int i=2,j=0;i<=n-bg+1;i++)
            {
                while(j>0&&s[bg+i-1]!=s[bg+j])
                    j=nxt[bg][j-1];
                if(s[bg+i-1]==s[bg+j]) j++;
                nxt[bg][i-1]=j;
            }
        }
        for(int len=2;len<=n;len++)
            for(int i=1;i+len-1<=n;i++)
            {
                int j=i+len-1;
                int &p=pre[i][j];
                p=i;
                for(int k=i+1;k<j;k++) if(f[i][p]+f[p+1][j]>f[i][k]+f[k+1][j]) p=k;
                f[i][j]=f[i][p]+f[p+1][j];
                int v=len-nxt[i][len-1];
                if(len%v==0)
                    for(int k=1;v*k<=len;k++)
                        if(len%(v*k)==0&&len/(v*k)>1&&f[i][i+v*k-1]+2+nd[len/(v*k)]<f[i][j])
                        {
                            f[i][j]=f[i][i+v*k-1]+2+nd[len/(v*k)];
                            p=-v*k;
                        }
            }
        print(1,n); puts("");
        return 0;
    }
    
    • 1

    信息

    ID
    1177
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者