F. 折叠序列

将一个序列折叠,求折叠后的序列的最短长度

AAAAAAAAA ABABAB CCD -> 9(A)3(AB)CCD

区间dp,两种情况:1. $ l \rightarrow r $ 由 \(l \rightarrow k\)\(k+1 \rightarrow r\) 两段合并

​ 2.由 \(l \rightarrow k\) 循环构成

to_string : 把一段数字转化为字符串形式

per(len,2,n) for(int l=1,r=len;r<=n;++l,++r)
{
    f[l][r]=r-l+1;//不折叠
    per(k,l,r-1)
    {
        f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);//情况1
        if(ck(l,r,k))//情况2
        {
            s=to_string((r-l+1)/(k-l+1));
            num=s.size();//括号前数字的长度
            f[l][r]=min(f[l][r],f[l][k]+num+2);
        }
    }
}
#include <bits/stdc++.h>
#define per(i,a,b) for(int i(a);i<=b;++i)
using namespace std;
const int N=110;
char a[N];
int f[N][N];
bool ck(int l,int r,int k)//判断是否能折叠
{
    int len=k-l+1;
    if((r-l+1)%len) return 0;
    per(i,0,r-l) if(a[l+i]!=a[l+(i%len)]) return 0;
    return 1;
}
void pt(int l,int r)//递归输出
{
    if(f[l][r]==r-l+1)//原长输出
    {
        per(i,l,r) printf("%c",a[i]);
        return;
    }
    per(k,l,r-1)
    {
        if(f[l][r]==f[l][k]+f[k+1][r])//分2段
        {
            pt(l,k),pt(k+1,r);
            return;
        }
        string s=to_string((r-l+1)/(k-l+1));
        int num=s.size();
        if(ck(l,r,k) && f[l][r]==f[l][k]+num+2)//折叠
        {
            printf("%d(",(r-l+1)/(k-l+1));
            pt(l,k);
            printf(")");
            return;
        }
    }
}
signed main()
{
	// freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    int n,num;
    string s;
    cin>>a+1;
    n=strlen(a+1);
    memset(f,0x3f,sizeof(f));
    per(i,1,n) f[i][i]=1;
    per(len,2,n) for(int l=1,r=len;r<=n;++l,++r)
    {
        f[l][r]=r-l+1;
        per(k,l,r-1)
        {
            f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
            if(ck(l,r,k))
            {
                s=to_string((r-l+1)/(k-l+1));
                num=s.size();
                f[l][r]=min(f[l][r],f[l][k]+num+2);
            }
        }
    }
    pt(1,n);
    return 0;
}
posted @ 2023-01-12 17:56  f2021yjm  阅读(18)  评论(0编辑  收藏  举报