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 }

 

posted @ 2021-04-06 00:26  acmloser  阅读(53)  评论(0编辑  收藏  举报