题目链接:Link
Problem
Solution
A+B型拼接的转移方程很显而易见,因此我们只要知道由循环构成的拼接。
可以考虑先预处理出每个数字的位数,然后最小循环节长度可以用kmp $ O(n^2) $ 预处理, $ O(1) $ 求出,由于我不会证最佳循环节长度一定是最小的,$ O(sqrt n) $ 枚举即可,总时间复杂度 $ O(n^3) $。(当然可以四边形不等式成 $ O(n^2 sqrt n) $ )
Code
#include<cstdio>
#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;
}