【UVA11022】String Factoring
Cry_For_theMoon · · 题解
传送门
这个和 【SCOI2003】字符串折叠还有 【SCOI2007】压缩,完全就是一类套路题。这个应该是这三道题中最简单的一道。这里给一个稳定
设
字符串的循环节是一个经典的问题,有一个很经典的性质(这里的循环节都是没有剩余):
- 若对于字符串
S , 有长度为len 的循环节(len\neq S) ,那么等价于len\mid S 且S[1...|S|-len] 是S 的公共前后缀。
整除不必讲了,而这两个前缀和后缀都是由
定义
虽然kmp跳转的复杂度不好算,但就算每次减1,那复杂度依旧是
代码非常简短:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define next Cry_For_theMoon
using namespace std;
const int MAXN=110;
char str[MAXN];
int n,next[MAXN][MAXN],f[MAXN][MAXN];
int main(){
while(1){
memset(str,0,sizeof str);
memset(next,0,sizeof next);
scanf("%s",str+1);
if(str[1]=='*')return 0;
n=strlen(str+1);
for(int i=1;i<=n;i++){
next[i][i]=0;
for(int j=i+1,v=0;j<=n;j++){
while(v && str[j] != str[i+v])v=next[i][v];
if(str[j]==str[i+v])v++;
next[i][j]=v;
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
f[i][j]=j-i+1;
}
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
//[i,j]
int v=next[i][j];
while(v){
if(len%(len-v)==0){
f[i][j]=min(f[i][j],f[i][i+len-v-1]);
}
v=next[i][v];
}
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
printf("%d\n",f[1][n]);
}
return 0;
}