P4302 [SCOI2003]字符串折叠
考察:区间DP
处理方式略像涂色...本蒟蒻是没想出来怎么转移....
思路:
实际就是暴力...本蒟蒻还想了怎么快速判断循环.....
对于枚举的区间[l,r],看是否是循环区间,如果不是要再看里面的子区间是否为循环区间,枚举子区间f[l][r] = min(f[l][k]+f[k+1][r],f[l][r])
对于循环区间f[l][r] = min(f[l][k]+nums[len/k]+2,f[l][r])//k为循环节长度.
时间复杂度O(n3)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int N = 110,INF = 0x3f3f3f3f; 6 char s[N]; 7 int n,nums[N],f[N][N]; 8 bool check(int l,int r,int len) 9 { 10 for(int i=l;i+len<=r;i++) 11 if(s[i]!=s[i+len]) return 0; 12 return 1; 13 } 14 void solve() 15 { 16 for(int len=2;len<=n;len++) 17 for(int l=1;l+len-1<=n;l++) 18 { 19 int r = l+len-1; 20 for(int k=1;k<len;k++) 21 if(len%k==0&&check(l,r,k))//检查[l,r]区间是否存在循环节 22 f[l][r] = min(f[l][r],f[l][l+k-1]+nums[len/k]+2); 23 for(int k=l;k<r;k++)//上面的循环只是检查[l,r]区间是否为循环节区间,如果不是要和非循环节区间拼接. 24 f[l][r] = min(f[l][k]+f[k+1][r],f[l][r]); 25 } 26 } 27 void init() 28 { 29 memset(f,0x3f,sizeof f); 30 for(int i=1;i<=n;i++) f[i][i] = 1; 31 for(int i=1;i<=100;i++) 32 { 33 if(i<10) nums[i] = 1; 34 else if(i<100) nums[i] = 2; 35 else nums[i] = 3; 36 } 37 } 38 int main() 39 { 40 scanf("%s",s+1); 41 n = strlen(s+1); 42 init(); 43 solve(); 44 printf("%d\n",f[1][n]); 45 return 0; 46 }