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;
}