BZOJ1090:[SCOI2003]字符串折叠——题解

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

Description

折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S=S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S)=SSSS…S(X个S)。 3. 如果A=A’, B=B’,则AB=A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B)=AAACBB,而2(3(A)C)2(B)=AAACAAACBB

给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。

Input

仅一行,即字符串S,长度保证不超过100。

Output

仅一行,即最短的折叠长度。

Sample Input

NEERCYESYESYESNEERCYESYESYES

Sample Output

14

——————————————————————————————————

我竟然自己做了一道dp!

f[i][j]表示i~j压缩后最短长度。

显然我们有:

for(int k=i;k<j;k++)f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);

接下来就是压缩了。

我们可以枚举区间长度的倍数,然后判断是否可以压缩,并且判断压缩之后是否会变的更小即可了!

复杂度看似O(n^3*根号n),但是实际上达不到,所以能过就是了。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=110;
int f[N][N];
char s[N];
inline int w(int x){
    if(x==100)return 5;
    if(x>=10)return 4;
    return 3;
}
bool check(int k,int l,int r,int len){
    for(int i=l+len;i<=r;i++){
    if(s[i-len]!=s[i])return 0;
    }
    return 1;
}
int main(){
    cin>>s+1;
    int n=strlen(s+1);
    for(int i=1;i<=n;i++)f[i][i]=1;
    for(int l=2;l<=n;l++){
    for(int i=1;i<=n-l+1;i++){
        int j=i+l-1;
        f[i][j]=l;
        for(int k=i;k<j;k++)f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
        for(int k=l;k>=1;k--){
        if(l%k)continue;
        int len=(j-i+1)/k;
        if(check(k,i,j,len)){
            if(f[i][j]>f[i][i+len-1]+w(k)){
            f[i][j]=f[i][i+len-1]+w(k);
            break;
            }
        }
        }
    }
    }
    printf("%d\n",f[1][n]);
    return 0;
}
posted @ 2018-01-08 15:49  luyouqi233  阅读(235)  评论(0编辑  收藏  举报