D2. Zero-One (Hard Version)

题意

给定n,x,y和两个01串,字符串的长度为n,现在你可以选择一个lr1l<rn),将al变成1al,将ar变成1arl+1=r,则代价是x,否则代价是y,操作次数不限,求使两个串相同的最小代价,若无解输出-1

题解

设两个01串有cnt个位置不同,如果cnt为奇数,显然无解

如果cnt是偶数,以下进行分类讨论

  1. xy

    特判一下cnt=2且这两个位置是相邻的情况,此时的答案为min(2y,x)

    否则,我们总可以选cnt/2组不相邻的位置(因为选相邻总是不优的),此时答案为cnt/2y

  2. x<y

​ 处理出所有两个01串不同的位置,原问题等价于把这些位置分成cnt/2组,每组的策略如下:

设这两个位置是lr,相邻的话显然直接操作,不相邻的话,直接操作或者移动某个位置,直到相邻后再操作

因此,最小代价为min(y,(rl)x)

​ 我们在pos数组上考虑区间dp,考虑区间[l,r],我们可以证明dp只有三种情况:l,l+1同组,r,r1同组,l,r同组
首先,同组的lr如果不相邻,那么其代价一定是y,因为在pos数组上跨过某点一定不会使答案更优
l+1<l1<r1<r1,如果l,l1一组,r1,r一组,那么基于以上结论,它们的代价只能都是y,而这一定不比[l,r],[l1,r1]这种选法优,且这种选法已经被考虑进了dp的l,r同组这种情况中去,因此,dp是正确的

预处理区间长度为2的情况,只dp区间长度为偶数的区间,答案即为f[1][cnt]

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5007;
ll n,x,y,a[N],b[N],f[N][N],pos[N];
void read(ll &x){
    char c=getchar();
    x=0;
    while(!isdigit(c)){
        c=getchar();
    }
    while(isdigit(c)){
        x=x*10+c-'0';
        c=getchar();
    }
}
ll read(){
    char c=getchar();
    while(c!='0'&&c!='1'){
        c=getchar();
    }
    return c-'0';
}
ll calc(ll l,ll r){
    return min((r-l)*x,y);
}
void work(){
    ll i,j,cnt=0;
    read(n),read(x),read(y);
    for(i=1;i<=n;++i){
        a[i]=read();
    }
    for(i=1;i<=n;++i){
        b[i]=read();
    }
    for(i=1;i<=n;++i){
        if(a[i]!=b[i]){
            pos[++cnt]=i;
        }
    }
    if(cnt%2){
        puts("-1");
        return;
    }
    if(x>=y){
        if(cnt==2&&pos[2]-pos[1]==1){
            printf("%lld\n",min(2*y,x));    
        }
        else{
            printf("%lld\n",cnt/2*y);
        }
    }
    else{
        for(i=1;i<cnt;++i){
            f[i][i+1]=calc(pos[i],pos[i+1]);
        }
        for(i=4;i<=cnt;i+=2){
            for(j=1;j+i-1<=cnt;++j){
                ll l=j,r=j+i-1;
                f[l][r]=min(min(f[l+2][r]+calc(pos[l],pos[l+1]),f[l][r-2]+calc(pos[r-1],pos[r])),
                f[l+1][r-1]+calc(pos[l],pos[r]));
            }
        }
        printf("%lld\n",f[1][cnt]);
    }
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        work();        
    }
    return 0;
}
posted @   DGJG  阅读(129)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示