【CodeForces】790 C. Bear and Company 动态规划

【题目】C. Bear and Company

【题意】给定大写字母字符串,交换相邻字符代价为1,求最小代价使得字符串不含"VK"子串。n<=75。

【算法】动态规划

【题解】关键在于表示状态,我们将确定下来的前若干个固定作为状态,后面新加的字符不会进入固定的前若干个。(为了方便,非'V''K'的字符皆为‘X')

由于相同字符显然不可能跨越,那么前若干个的有效信息只有:它是由前v个’V',前k个‘K',前x个’X'组成的,最后一个字符是否’V',即f[v][k][x][0/1]。

转移时枚举新加入的字符,问题在于统计新加入字符前有多少未固定字符,就是加入这个字符的代价。

假设0是'V',1是‘K',2是’X',很容易预处理p[i][0]表示第i个'V'的位置,c[i][0]表示前i个位置‘V'的数量(1和2同理),然后就很容易计算了。

如果推不清楚可以参考代码,很好理解。

复杂度O(n^3)。

#include<cstdio>
#include<cstring>
int n,p[110][3],c[110][3],f[110][110][110][2],V,K,X;
char s[110];
int min(int a,int b){return a<b?a:b;}
int r(int o,int v,int k,int x){return o-min(c[o][0],v)-min(c[o][1],k)-min(c[o][2],x);}
int main(){
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++){
        for(int j=0;j<3;j++)c[i][j]=c[i-1][j];
        if(s[i]=='V')V++,p[V][0]=i,c[i][0]++;else
        if(s[i]=='K')K++,p[K][1]=i,c[i][1]++;else
        X++,p[X][2]=i,c[i][2]++;
    }
    memset(f,0x3f,sizeof(f));
    f[0][0][0][0]=0;
    for(int i=0;i<=V;i++)
        for(int j=0;j<=K;j++)
            for(int k=0;k<=X;k++){
                int Q=min(f[i][j][k][0],f[i][j][k][1]);
                f[i+1][j][k][1]=min(f[i+1][j][k][1],Q+r(p[i+1][0],i+1,j,k));
                f[i][j+1][k][0]=min(f[i][j+1][k][0],f[i][j][k][0]+r(p[j+1][1],i,j+1,k));
                f[i][j][k+1][0]=min(f[i][j][k+1][0],Q+r(p[k+1][2],i,j,k+1));
            }
    printf("%d",min(f[V][K][X][0],f[V][K][X][1]));
    return 0;
}
View Code

 

posted @ 2018-03-14 08:07  ONION_CYC  阅读(...)  评论(...编辑  收藏