题解:AT_agc019_d [AGC019D] Shift and Flip
题目传送门
题意
给出两个
分析
首先我们分类讨论,如果把所有操作看成一个操作序列,我们会发现一个规律。无论是什么样的序列,它的操作序列一定满足对于位置
我们考虑怎么样枚举这些操作,我们注意到,从位置
现在假定我们确定了移动距离
那么如果这段区间不存在
因为这只是对右边平移的情况,所以之后还要再做一次对左边的处理。
同时注意要化链成环,所以我在代码中复制了一份相同的序列
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1010101;
ll n,a[N],b[N],f[N],pre[N],nxt[N],sa,sb,ans=1e18;
struct node{ll l,r;}p[N];
bool cmp(node a,node b){
if(a.l==b.l)return a.r<b.r;
return a.l>b.l;
}
void solvel(ll x){
ll pos=x,tot=0;
for(int i=1;i<=n;i++){
if(!a[i]&&b[i+x])pos++;
if(a[i]&&!b[i+x]){
pos++;
if(!(f[i+x]-f[i-1]))p[++tot]={pre[i+n],nxt[i+x]};
}
}
sort(p+1,p+tot+1,cmp);
p[tot+1]={0,0};
ll maxn=0;
for(int i=1;i<=tot+1;i++){
ans=min(ans,pos+(maxn+p[i].l)*2);
maxn=max(maxn,p[i].r);
}
}
void solver(ll x){
ll pos=-x,tot=0;
for(int i=n+1;i<=2*n;i++){
if(!a[i]&&b[i+x])pos++;
if(a[i]&&!b[i+x]){
pos++;
if(!(f[i]-f[i+x-1]))p[++tot]={pre[i+x],nxt[i-n]};
}
}
sort(p+1,p+tot+1,cmp);
p[tot+1]={0,0};
ll maxn=0;
for(int i=1;i<=tot+1;i++){
ans=min(ans,pos+(maxn+p[i].l)*2);
maxn=max(maxn,p[i].r);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
string s1,s2;
cin>>s1>>s2;
n=s1.size();
s1=" "+s1;
s2=" "+s2;
for(int i=1;i<=n;i++)a[i]=s1[i]-'0',b[i]=s2[i]-'0',sa+=a[i],sb+=b[i];
if(sa&&!sb){
cout<<-1;
return 0;
}
for(int i=1;i<=n;i++)a[i+n]=a[i],b[i+n]=b[i];
for(int i=1;i<=2*n;i++)f[i]=f[i-1]+b[i];
for(int i=1;i<=2*n;i++){
pre[i]=pre[i-1]+1;
if(b[i])pre[i]=0;
}
for(int i=2*n;i>=1;i--){
nxt[i]=nxt[i+1]+1;
if(b[i])nxt[i]=0;
}
for(int i=1;i<=n;i++)solvel(i-1);
for(int i=1;i<=n;i++)solver(1-i);
cout<<ans;
return 0;
}