洛谷 4302 BZOJ 1090 SCOI2003 字符串折叠 UVA1630 Folding(输出方案版)
【题解】
区间DP. 设f[i][j]表示i~j的最小代价。再枚举中间点k,很容易想到转移方程为f[i][j]=min(f[i][j],f[i][k]+f[k][j]),同时如果i~k可以通过重复获得i~j,那么f[i][j]=min(f[i][j],f[i][k]+len(x)+2),这里的len(x)是指重复次数在十进制下有多少位。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 #define rg register 6 #define N 200 7 using namespace std; 8 int n,m,f[N][N]; 9 char s[N]; 10 inline int read(){ 11 int k=0,f=1; char c=getchar(); 12 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 13 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 14 return k*f; 15 } 16 inline bool check(int l,int r,int end){ 17 int l1=r-l+1,l2=end-l+1; 18 if(l2%l1) return 0; 19 m=l2/l1; 20 for(rg int i=1;i<=m;i++){ 21 int st=l+(i-1)*l1; 22 for(rg int j=0;j<l1;j++) if(s[l+j]!=s[st+j]) return 0; 23 } 24 return 1; 25 } 26 inline int qlen(int x){ 27 int cnt=0; 28 while(x){ 29 x/=10; 30 cnt++; 31 } 32 return cnt; 33 } 34 int main(){ 35 scanf("%s",s+1); n=strlen(s+1); 36 for(rg int i=0;i<=n;i++) 37 for(rg int j=i;j<=n;j++) f[i][j]=j-i+1; 38 for(rg int l=0;l<=n;l++){ 39 for(rg int i=1;i+l-1<=n;i++){ 40 int j=i+l-1; 41 for(rg int k=i;k<=j;k++){ 42 f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]); 43 if(check(i,k,j)){ 44 f[i][j]=min(f[i][j],f[i][k]+2+qlen(m)); 45 // printf("%d %d %d\n",i,k,j); 46 } 47 } 48 } 49 } 50 printf("%d\n",f[1][n]); 51 return 0; 52 }
输出方案的版本。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 #define rg register 6 #define N 200 7 using namespace std; 8 int n,m,f[N][N],ans[N],from[N][N]; 9 char s[N]; 10 inline int read(){ 11 int k=0,f=1; char c=getchar(); 12 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 13 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 14 return k*f; 15 } 16 inline bool check(int l,int r,int end){ 17 int l1=r-l+1,l2=end-l+1; 18 if(l2%l1) return 0; 19 m=l2/l1; 20 for(rg int i=1;i<=m;i++){ 21 int st=l+(i-1)*l1; 22 for(rg int j=0;j<l1;j++) if(s[l+j]!=s[st+j]) return 0; 23 } 24 return 1; 25 } 26 inline int qlen(int x){ 27 int cnt=0; 28 while(x){ 29 x/=10; 30 cnt++; 31 } 32 return cnt; 33 } 34 void out(int l,int r){ 35 if(f[l][r]==r-l+1){ 36 for(rg int i=l;i<=r;i++) printf("%c",s[i]); 37 return; 38 } 39 int k=from[l][r]; 40 if(check(l,k,r)){ 41 printf("%d(",m); 42 out(l,k); 43 printf(")"); 44 } 45 else{ 46 out(l,k); out(k+1,r); 47 } 48 } 49 int main(){ 50 while(scanf("%s",s+1)!=EOF){ 51 n=strlen(s+1); 52 for(rg int i=0;i<=n;i++) 53 for(rg int j=i;j<=n;j++) f[i][j]=j-i+1; 54 for(rg int l=0;l<=n;l++){ 55 for(rg int i=1;i+l-1<=n;i++){ 56 int j=i+l-1; 57 for(rg int k=i;k<=j;k++){ 58 if(f[i][k]+f[k+1][j]<f[i][j]){ 59 f[i][j]=f[i][k]+f[k+1][j]; 60 from[i][j]=k; 61 } 62 if(check(i,k,j)){ 63 int tmp=f[i][k]+2+qlen(m); 64 if(tmp<f[i][j]){ 65 f[i][j]=tmp; 66 from[i][j]=k; 67 } 68 // printf("%d %d %d\n",i,k,j); 69 } 70 } 71 } 72 } 73 out(1,n); 74 puts(""); 75 } 76 // printf("%d\n",f[1][n]); 77 return 0; 78 }