[SCOI2007]压缩——区间dp

题目链接:https://www.luogu.com.cn/problem/P2470

分析:

这道题我是看题解2过的,但是对代码的理解存在问题,所以自个口胡一下。

对于0与1两种状态,我们先考虑1:很明显1要在0的基础上进行,f[l][r][1]=min(f[l][r][1],min(f[l][k][0],f[l][k][1])+min(f[k+1][r][0],f[k+1][r][1])+1),这里面的+1就是补M的操作,假如在l到r没有对称的话,这里+1明显不会作为答案,当+1作为答案时,前面两个min一定是取了有R的情况,也就是说,我们把M和R的放入操作分开,M是因为R才放入的。这么理解起来的话,前面0操作对M置之不理也就变得合理起来。

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
#define R register
#define debug printf("zjy\n")
inline int read(){
    int a=0,b=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')b=-1;c=getchar();}
    while(isdigit(c)){a=a*10+c-'0';c=getchar();}
    return a*b;
}
int n,f[100][100][2];
char s[100];
bool check(int l,int r){
    if((r-l+1)&1)return false;
    int mid=(l+r)>>1;
    for(R int i=0;i<((r-l+1)>>1);i++){
        if(s[l+i]!=s[mid+1+i])return false;
    }
    return true;
}
signed main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    memset(f,0x3f,sizeof(f));
    for(R int i=1;i<=n;i++){
        for(R int j=i;j<=n;j++){
            f[i][j][0]=f[i][j][1]=j-i+1;
        }
    }
    for(R int len=2;len<=n;len++){
        for(R int l=1,r,mid;l+len-1<=n;l++){
            r=l+len-1;mid=(l+r)>>1;
            if(check(l,r))f[l][r][0]=min(f[l][r][0],f[l][mid][0]+1);
            for(R int k=l;k<r;k++)f[l][r][0]=min(f[l][r][0],f[l][k][0]+r-k);
            for(R int k=l;k<r;k++)f[l][r][1]=min(f[l][r][1],min(f[l][k][0],f[l][k][1])+min(f[k+1][r][0],f[k+1][r][1])+1);
        }
    }
    printf("%lld\n",min(f[1][n][0],f[1][n][1]));
    return 0;
}

 

posted @ 2020-08-21 15:20  zjy1412  阅读(112)  评论(0编辑  收藏  举报