Codeforces Global Round 10 G. Omkar and Pies(状压dp)

题目

长度为k(k<=20)的01串s[]和t[],不保证二者的01数量相同,

现在有n(n<=1e6)个小精灵,

第i个小精灵可以把s串的第ai和第bi两个位置的值互换,

现在你要选择一个长度至少为m(m<=n)的连续区间,

不妨设为[l,r],则需要依次将(al,bl)...(ar,br)这些位置的值互换,

你需要令操作后的s[],和t[]的相似度最大,相似度定义为对应位置数字相同的个数

输出这个最大相似度,并输出操作的连续区间的左右端点[l,r]

思路来源

官方题解+boboniu代码

题解

首先,如果固定左端点l,则顺序执行操作至右端点r即可,但l操作转移到l+1时,比较难撤销掉,

所以,可以考虑将t串也进行一次l操作,二者位置同时换,则抵消掉了l的影响

开一个映射,p[]表示当前的数组始终执行换位操作,p[i]表示最初第i位的值现在在pi的位置,

 

题解1:

官方题解,

记s串中1的数量为o1,t串中1的数量为o2,

二者公共的1的数量为same,二者不相同的位数为x,相似度为y,串长为k

则,o1+o2-2*same=x=y-k,为了最大化y,则最大化same,所以最大相似度和最大公共1是等价的,

dp[0][state]表示s串换成state这个状态最左端的操作下标l,

dp[1][state]表示t串换成state这个状态最右端的操作下标r,

如果r-l>=m,说明[l+1,r]这段操作可行,

但实际二者的state可能并不完全一致,所以sosdp枚举子集,将子集的状态的l和r更新,

倒序枚举子集并下放,找到state相同的满足r-l>=m的状态来更新答案,

其中state中1的个数被认为是最大公共1的个数,统计即可

 

题解2:

dp两个数组仍与题解1一致,考虑固定一个,用另一个去更新状态

枚举扰动值c,表示当前dp[0][state]中,state最多允许发生c位变化时,最左端的操作下标l

有c位是错乱的情况下,答案为k-c,转移则考虑本轮将dp[0][state]中的一位1发生变化,使其更新相邻状态的l值

代码1

#include<bits/stdc++.h>
using namespace std;
const int N=20,M=1<<20,INF=0x3f3f3f3f;
int n,m,k,a,b,x,y,o1,o2;
int ans,pl,pr;
int dp[2][M+5],p[N+5];
char s[N+5],t[N+5];
void g(int &x,int &y){
    x=y=0;
    for(int j=0;j<k;++j){
        if(s[j]=='1')x|=(1<<p[j]);
        if(t[j]=='1')y|=(1<<p[j]);
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s%s",s,t);
    for(int i=0;i<k;++i){
        p[i]=i;
        o1+=(s[i]=='1');
        o2+=(t[i]=='1');
    }
    memset(dp[0],INF,sizeof dp[0]);//min
    memset(dp[1],0,sizeof dp[1]);//max
    g(x,y);dp[0][x]=0;dp[1][y]=0;
    for(int i=1;i<=n;++i){
        scanf("%d%d",&a,&b);
        a--;b--;swap(p[a],p[b]);
        g(x,y);dp[0][x]=min(dp[0][x],i);dp[1][y]=max(dp[1][y],i);
    }
    for(int i=(1<<k)-1;i>=0;--i){
        int tmp=k-(o1+o2-2*__builtin_popcount(i));
        if(dp[1][i]-dp[0][i]>=m){
            if(ans<tmp){
                ans=tmp;
                pl=dp[0][i]+1;//dp[0][i]:[1,l-1]
                pr=dp[1][i];//dp[1][i]:[1,r]
            }
        }
        for(int j=0;j<k;++j){
            if(i>>j&1){
                dp[0][i^(1<<j)]=min(dp[0][i^(1<<j)],dp[0][i]);
                dp[1][i^(1<<j)]=max(dp[1][i^(1<<j)],dp[1][i]);
            }
        }
    }
    printf("%d\n",ans);
    printf("%d %d",pl,pr);
	return 0;
}

代码2

#include<bits/stdc++.h>
using namespace std;
const int N=20,M=1<<20,INF=0x3f3f3f3f;
int n,m,k,a,b,x,y;
int dp[2][M+5],p[N+5],tmp[M+5];
char s[N+5],t[N+5];
void g(int &x,int &y){
    x=y=0;
    for(int j=0;j<k;++j){
        if(s[j]=='1')x|=(1<<p[j]);
        if(t[j]=='1')y|=(1<<p[j]);
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s%s",s,t);
    for(int i=0;i<k;++i){
        p[i]=i;
    }
    memset(dp[0],INF,sizeof dp[0]);//min
    memset(dp[1],0,sizeof dp[1]);//max
    g(x,y);dp[0][x]=0;dp[1][y]=0;
    for(int i=1;i<=n;++i){
        scanf("%d%d",&a,&b);
        a--;b--;swap(p[a],p[b]);
        g(x,y);dp[0][x]=min(dp[0][x],i);dp[1][y]=max(dp[1][y],i);
    }
    for(int c=0;c<=k;++c){
        for(int i=0;i<(1<<k);++i){
            if(dp[1][i]-dp[0][i]>=m){
                printf("%d\n",k-c);
                printf("%d %d",dp[0][i]+1,dp[1][i]);
                return 0;
            }
        }
        for(int i=0;i<(1<<k);++i){
            tmp[i]=dp[0][i];
            for(int j=0;j<k;++j){
                tmp[i]=min(tmp[i],dp[0][i^(1<<j)]);
            }
        }
        for(int i=0;i<(1<<k);++i){
            dp[0][i]=tmp[i];
        }
    }
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据提供的引用内容,Codeforces Round 511 (Div. 1)是一个比赛的名称。然而,引用内容中没有提供与这个比赛相关的具体信息或问题。因此,我无法回答关于Codeforces Round 511 (Div. 1)的问题。如果您有关于这个比赛的具体问题,请提供更多的信息,我将尽力回答。 #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces Round 867 (Div. 3)(A题到E题)](https://blog.csdn.net/wdgkd/article/details/130370975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值