• CF1392G Omkar and Pies【状压DP】


    CF1392G Omkar and Pies

    Description

    给定两个长度为 (k)(01) 串,分别是起始串和目标串。

    依次给出 (n) 个可选操作,第 (j) 个操作 (a_j,b_j) 表示交换起始串的 (a_j) 位置与 (b_j) 位置。

    你需要选择操作序列中其中连续的一段操作依次按顺序执行,并且选择的操作数量不小于 (m)

    你需要让操作完成后的串与目标串对应相同的位置数量尽可能多。

    输出最大数量与你选取操作的区间(若有多种方案输出任意一个即可)。

    (kle 20,mle nle 10^6)

    Solution

    首先执行 ([l,r]) 的区间操作可以转化为,对起始串进行 ([l,n]) 操作,再对目标串进行 ([r+1,n]) 操作,这样一来 ([r+1,n]) 的操作相当于被抵消了,就跟原问题一样了。

    首先可以 (mathcal O(nk)) 预处理出对起始串与目标串执行所有后缀操作得到的序列,设分别为 ({a_n})({b_n})

    现在我们等于需要最大化 (a_i)(b_j) 的相同字符数量,并使 (j-ige m),设 (x)(a_i)(1) 的个数,(y)(b_j)(1) 的个数,(z)(a_i)(b_j) 同时为 (1) 的位置数量,因此对应相同的位置数量就等于:

    [z+(k-x-y+z)=2z+k-x-y ]

    由于 (x,y) 是确定的,因此只需要最大化 (z)。枚举最终公共 (1) 的位置为 (s),求出:

    [dp_{0,s}=min i[ssubset a_i]\ dp_{1,s}=max i[ssubset b_i] ]

    如果 (dp_{1,s}-dp_{0,s}ge m) ,就可以用 (popcount(s)) 来更新答案了,于是预处理 (a,b,dp) 的复杂度都是 (mathcal O(nk))。总复杂度为 (mathcal O(nk)),可以通过此题。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=(1<<20)+20;
    int n,m,k,a,b,L[N],R[N],c[N],f[N],g[N],tmp[N][21],ret[21];
    char s[21],t[21];
    int main(){
    //	freopen("option2.in","r",stdin);
    	scanf("%d%d%d",&n,&m,&k);
    	scanf("%s",s+1);
    	int cta=0,ctb=0;
    	for(int i=1;i<=k;++i){
    		a=(a<<1)+s[i]-'0';
    		if(s[i]=='1') cta++;
    	}
    	scanf("%s",t+1);
    	for(int i=1;i<=k;++i){
    		b=(b<<1)+t[i]-'0';
    		if(t[i]=='1') ctb++;
    	}
    	for(int i=0;i<(1<<k);++i) f[i]=n+1,g[i]=0;
    	for(int i=1;i<=n;++i) scanf("%d%d",&L[i],&R[i]);
    	for(int i=1;i<=k;++i) ret[i]=i;
    	for(int i=n;i>=1;--i){
    		for(int j=1;j<=k;++j) tmp[i][j]=j;
    		swap(tmp[i][L[i]],tmp[i][R[i]]);
    		for(int j=1;j<=k;++j) ret[j]=tmp[i][ret[j]];
    		a=0;
    		for(int j=1;j<=k;++j) a=(a<<1)+s[ret[j]]-'0';
    		f[a]=min(f[a],i);
    	}
    	g[b]=n+1;
    	for(int i=1;i<=k;++i) ret[i]=i;
    	for(int i=n;i>=1;--i){
    		for(int j=1;j<=k;++j) tmp[i][j]=j;
    		swap(tmp[i][L[i]],tmp[i][R[i]]);
    		for(int j=1;j<=k;++j) ret[j]=tmp[i][ret[j]];
    		b=0;
    		for(int j=1;j<=k;++j) b=(b<<1)+t[ret[j]]-'0';
    		g[b]=max(g[b],i);
    	}
    	int ans=-1,reta=0,retb=0;
    	for(int i=((1<<k)-1);~i;--i){
    		int ct=0;
    		for(int j=0;j<k;++j){
    			if(i&(1<<j)){
    				ct++;
    				int tmp=i^(1<<j);
    				f[tmp]=min(f[tmp],f[i]);
    				g[tmp]=max(g[tmp],g[i]);
    			}
    		}
    		if(g[i]-f[i]>=m){
    			int ret=k-cta-ctb+ct+ct;
    			if(ret>ans) ans=ret,reta=f[i],retb=g[i]-1;
    		}
    	}
    	printf("%d
    %d %d",ans,reta,retb);
    	return 0;
    }
    
  • 相关阅读:
    正则表达式匹配整数和小数
    解决任务计划程序未启动任务,因为相同任务的实例正在运行的问题
    ActiveMQ 消息持久化到数据库(Mysql、SQL Server、Oracle、DB2等)
    C# CLR20R3 程序终止的几种解决方案
    彻底消除wine中文乱码,QQ,kugoo等等....
    Fedora如何添加第三方软件源?
    [转]Fedora 下安装NVIDIA显卡驱动(使用后无法进入图形界面)
    向fedora添加rpmfusion源
    [转]Java 8 Optional类深度解析(null处理)
    [转载]深入理解Java 8 Lambda
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14931659.html
Copyright © 2020-2023  润新知