一道很裸的区间Dp,不过我判断这个字符串的最小循环节时用了kmp,结果后来去看了一下别人的题解,发现,枚举就可以了。。。
具体的不写了。
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> using namespace std; char ss[300]; int n,nex[300],t,dp[300][300]; int get(int x) { int tot=0; while (x) tot++,x=x/10; return tot; } int calc(int lef,int righ) //用kmp计算当前字符串是否拥有最小循环节? { nex[0]=-1; int now=-1; for (int i=lef+1;i<=righ;i++) { while ((now!=-1)&&(ss[now+1+lef]!=ss[i])) now=nex[now]; if (ss[now+1+lef]==ss[i]) now++; nex[i-lef]=now; } int sum=righ-lef+1,tot=sum-nex[righ-lef]-1; if ((sum%tot==0)&&(tot<sum)) return min(sum,get(sum/tot)+2+dp[lef][lef+tot-1]); return sum; } int main() { scanf("%d",&t); while (t--) { scanf("%s",ss); int n=strlen(ss); int j=0; for (int len=1;len<=n;len++) for (int i=0;i<n-len+1;i++) { j=i+len-1; dp[i][j]=calc(i,j);//dp转移 for (int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); } printf("%d\n",dp[0][n-1]); } return 0; }