山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 1090 [SCOI2003]字符串折叠(区间DP)

 

【题目链接】

 

    http://www.lydsy.com/JudgeOnline/problem.php?id=1090

 

【题意】

 

    给定一个字符串,问将字符串折叠后的最小长度。

 

【思路】

 

    设f[i][j]表示将区间ij折叠后的最小长度,则有转移式:

        f[i][j]=min{ j-i+1,f[i][k]+f[k+1][j],f[i][i+x-1]+2+digit((j-i+1)/x) }

    第一项代表不折叠,第二项代表当前不折叠,第三项代表以x长度折叠ij区间,条件是满足ij区间以x为循环节。

 

【代码】

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 
 6 const int N = 5e2+10;
 7 
 8 int n;
 9 char s[N];
10 int f[N][N];
11 
12 int digit(int x) 
13 {
14     return x<10? 1:(x<100?2:3);
15 }
16 int dp(int l,int r) 
17 {
18     int& ans=f[l][r];
19     if(ans>=0) return ans;
20     if(l==r) return ans=1;
21     int len=r-l+1; ans=len;
22     for(int k=l;k<r;k++)
23         ans=min(ans,dp(l,k)+dp(k+1,r));
24     for(int x=1;x<=len;x++) if(len%x==0) {
25         int flag=0;
26         for(int i=l;i<=l+x-1;i++) {
27             int j=i+x;
28             while(j<=r) {
29                 if(s[i]!=s[j]) { flag=1; break; }
30                 j+=x;
31             }
32             if(flag==1) break;
33         }
34         if(!flag) ans=min(ans,dp(l,l+x-1)+2+digit(len/x));
35     }
36     return ans;
37 }
38 
39 int main()
40 {
41     scanf("%s",s);
42     n=strlen(s);
43     memset(f,-1,sizeof(f));
44     printf("%d\n",dp(0,n-1));
45     return 0;
46 }

 

    

posted on 2016-03-20 10:01  hahalidaxin  阅读(322)  评论(0编辑  收藏  举报