正题
题目链接:https://www.luogu.com.cn/problem/P4302
题目大意
一个字符串,对于一个字符串AAA。可以将连续的nnn个AAA缩成n(A)n(A)n(A)。求最短的长度能够表述出给定字符串
解题思路
定义fi,jf_{i,j}fi,j表示表示出i∼ji\sim ji∼j的字符串的最短方法。那么不考虑折叠的话有正常区间dpdpdp转移即fi,j=min{fi,k+fk+1,j}(i≤k<j)f_{i,j}=min\{f_{i,k}+f_{k+1,j}\}(i\leq k<j)fi,j=min{fi,k+fk+1,j}(i≤k<j)
然后对于一段区间[l,r][l,r][l,r]考虑折叠,我们枚举长度lenlenlen的约数kkk,判断能否用长度为kkk的字符串折叠。有转移fi,j=min{fi,i+k−1+2+zlen/k}(k−>[i,j])f_{i,j}=min\{f_{i,i+k-1}+2+z_{len/k}\}(k->[i,j])fi,j=min{fi,i+k−1+2+zlen/k}(k−>[i,j])(ziz_izi表示iii的位数)
时间复杂度O(n3n)O(n^3\sqrt n)O(n3n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,z[110],f[110][110];
char s[110];
bool check(int l,int r,int len){if((r-l+1)%len!=0)return 0;for(int i=l+len;i<=r;i++)if(s[i-len]!=s[i])return 0;return 1;
}
int main()
{scanf("%s",s+1);n=strlen(s+1);memset(f,0x3f,sizeof(f));for(int i=1;i<=n;i++)z[i]=z[i/10]+1,f[i][i]=1;for(int l=2;l<=n;l++){for(int i=1;i+l-1<=n;i++){int j=i+l-1;for(int k=i;k<j;k++)f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);for(int k=1;k<l;k++)if(check(i,j,k))f[i][j]=min(f[i][j],f[i][i+k-1]+2+z[l/k]);}}printf("%d",f[1][n]);
}