洛谷 P4302 [SCOI2003]字符串折叠 题解

每日一题 day68 打卡

Analysis

这道题很容易想到区间DP,但是在DP中还需要判断循环节的压缩这种情况。

另外还有一点,缩写并不一定比之前的字符串优。

eg. aaa -> 3(a)

于是我们开始考虑如何处理压缩的情况。

因为我们转移时是将两个子区间的答案合成到一个大区间内,即 dp[i][k] 和 dp[k+1][j] 推出 dp[i][j]

所以我们不妨设 dp[i][k] 所表示的区间为循环节,如果判断该循环节合法,那么压缩后的答案即为循环节的答案 + 2 + 数字位数。

于是我们得出 dp 方程:

dp[ i ][ j ] = min( dp[ i ][ j ] , dp[ i ][ k ] + dp[ k + 1 ][ j ] ); //正常更新答案

if (循环节合法) dp[ i ][ j ] = min( dp[ i ][ j ] , dp[ i ][ k ] + 2 + digit[ len / cyc ] ); //len为枚举的总区间长度,cyc为循环节长度

那么现在唯一的问题就是如何判断循环节合法

以下为限制条件:

1.如果枚举的总区间长度可以整除循环节的长度

2.判断 dp[ k + 1 ][ j ] 是否满足循环节 (这里的实现基本是暴力,看代码,很好懂)

这样这道题就完成了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 #define maxn 100+10
 7 #define rep(i,s,e) for(register int i=s;i<=e;++i)
 8 #define dwn(i,s,e) for(register int i=s;i>=e;--i)
 9 using namespace std;
10 inline int read()
11 {
12     int x=0,f=1;
13     char c=getchar();
14     while(c<'0'||c>'9') {if(c=='-') x=-x; c=getchar();}
15     while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
16     return f*x;
17 }
18 inline void write(int x)
19 {
20     if(x<0){putchar('-');x=-x;}
21     if(x>9)write(x/10);
22     putchar(x%10+'0');
23 }
24 int n;
25 int digit[maxn];
26 int dp[maxn][maxn];
27 char a[maxn];
28 inline bool check(int l,int r,int len)
29 {
30     for(register int i=l;i<=l+len-1;++i)
31     {
32         char ch=a[i];
33         for(register int j=i;j<=r;j+=len)
34         {
35             if(a[j]!=ch) return false;
36         }
37     }
38     return true;
39 }
40 signed main()
41 {
42     cin>>a+1;
43     n=strlen(a+1);
44     rep(i,1,9) digit[i]=1;
45     rep(i,10,99) digit[i]=2;
46     digit[100]=3;
47     memset(dp,63,sizeof(dp));
48     rep(i,1,100) dp[i][i]=1;
49     rep(len,1,n)
50     {
51         for(register int i=1;i+len-1<=n;++i)
52         {
53             int j=i+len-1;
54             rep(k,i,j-1)
55             {
56                 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
57                 int cyc=k-i+1;
58                 if(len%cyc!=0) continue;
59                 if(check(i,j,cyc)==true)
60                 {
61                     dp[i][j]=min(dp[i][j],dp[i][k]+2+digit[len/cyc]);
62                 }
63             }
64         }
65     }
66     write(dp[1][n]);
67     return 0;
68 }

如有失误请各位大佬斧正(反正我不认识斧正是什么意思)

posted @ 2020-02-27 14:41  handsome_zyc  阅读(166)  评论(0编辑  收藏  举报