zoukankan      html  css  js  c++  java
  • Agc019_D Shift and Flip

    传送门

    题目大意

    给定两个长为$n$的$01$串$A,B$,每次操作有三种

    将$A$整体向左移动,并将$A_1$放在原来$A_n$的位置上。

    将$A$整体向有移动,并将$A_n$放在原来$A_1$的位置上。

    选择一个位置$i$使得$B_i=1$,将$A_i$变为$1-A_i$。

    求将$A$变为$B$的最小操作数,若无解输出$-1$。

    $nleq 2000$

    题解

    首先当$A$有$1$,$B$没有$1$那么一定无解。当$A,B$均没有$1$时代价为$0$

    其余情况$B$中一定有$1$,将$A$的环状移动用将$B$左右倍长为$3$倍,$A$直接左右移动。

    对于$A$中每一个位置$i$,预处理每一个$i$需要向左和向右最少移动多少步才能使得$A_i$对应了一个$B_j$使得$B_j=1$,记为$L_i,R_i$。

    接着,考虑暴力枚举最终$A$在与原来的相对位置与$B$对应,假设$A$与原来的位置相对向右移动了$k$个,然后对于每一个$A_i e B_{i+k}$,我们至少将$A$左移$L_i$位或右移$R_i$。

    假设我们最终要向右移动$k$位与$B$对应,考虑枚举先向左走了$x$步,那么对于所有$L_ileq x$对答案无影响了,只需要统计对$L_i>x$的$R_i$最大值(记为$RS$),那么但就是先向左移$x$步再移回来,再向右移到$RS$,最后移到$k$显然是最优的方案,过程中要对哦每一个$A_i e B_{i+k}$的进行一步操作,记为$m$个,那么就用$2x+RS+|RS-k|+m$来更新答案。

    将$A$向左移动同理。

    复杂度$O(n^2)$

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define M 8010
    using namespace std;
    int n,m,p[M],t[M],L[M],R[M]; char s1[M],s2[M];
    int pre[M],suf[M],ls[M],rs[M],ct1,ct2,ans; 
    bool cmp(int x,int y){return L[x]>L[y]||(L[x]==L[y]&&R[x]<R[y]);}
    void upd(int tar,int hd,int rev,int con){
    	if(tar>=hd) ans=min(ans,rev*2+tar+con);
    	else ans=min(ans,rev*2+(hd*2-tar)+con);
    }
    int main(){
    	scanf("%s%s",s1+1,s2+1),n=strlen(s1+1),ans=n*n;
    	for(int i=1;i<=n;i++) p[i]=s1[i]-'0',t[i]=t[i+n]=t[i+n+n]=s2[i]-'0';
    	for(int i=1;i<=n;i++) ct1+=p[i],ct2+=t[i];
    	if(!ct2){puts(ct1?"-1":"0");return 0;}
    	for(int i=1;i<=n+n;i++) if(!t[i]) ls[i]=(ls[i-1]+1);
    	for(int i=n+n+n;i>n;i--) if(!t[i]) rs[i]=(rs[i+1]+1);
    	for(int k=0;k<=n;k++){
    		m=0,memset(pre,0,sizeof(pre)),memset(suf,0,sizeof(suf));
    		for(int i=1;i<=n;i++){
    			if(p[i]^t[i+k]){
    				m++; if(t[i+k]) continue;
    				pre[ls[i+n]]=max(pre[ls[i+n]],rs[i+n]);
    				suf[rs[i+n]]=max(suf[rs[i+n]],ls[i+n]);
    			}
    		}
    		for(int i=n-1;i>=0;i--) suf[i]=max(suf[i],suf[i+1]),pre[i]=max(pre[i],pre[i+1]);
    		for(int i=0;i<n;i++) upd(k,pre[i+1],i,m),upd(n-k,suf[i+1],i,m);
    	} printf("%d
    ",ans); return 0;
    }
  • 相关阅读:
    Java8新特性2 lambda表达式
    Java8新特性1
    多线程与高并发(2)Volatile+CAS
    多线程与高并发 Synchronize
    《重构:改善既有代码的设计》读书笔记5 简化函数调用
    《重构:改善既有代码的设计》读书笔记4 简化条件表达式
    mysql语法大全使用篇
    《重构:改善既有代码的设计》读书笔记3 重新组织数据
    《重构:改善既有代码的设计》读书笔记2 在对象之间搬移特性
    《重构:改善既有代码的设计》读书笔记1——重新组织函数
  • 原文地址:https://www.cnblogs.com/OYJason/p/9830552.html
Copyright © 2011-2022 走看看