题目链接
https://atcoder.jp/contests/agc030/tasks/agc030_e
题解
又是个奇妙转化题。。
当我们反转一个位置时,该位置左右的数一定不一样。那么假设我们把左边是0
右边是1
的连续两个位置之间画一道红线,左边是1
右边是0
的连续两个位置之间画一道蓝线,为了处理边界问题我们假设首尾处都有无限多的红线和蓝线且整个序列满足红蓝交替。那么我们的操作可以等价为把一条线向左或向右移动(1)个位置,且移动后满足整个序列依然红蓝交替且任何两条相邻的线(除首尾外)间距为(1)或(2).
假设我们确定了两个序列中所有线的对应关系,那么答案就是对应线位置差的绝对值之和。显然可以构造出一种代价为此的方案,而由于任何相邻两个位置相差不超过(2), 一定不存在两条相邻的线,满足一条线的目标位置在其之左,另一条线的目标位置在其之右。那么我们可以用“不动线”将这个序列分为若干段,每一段里全是向左或者全是向右,这显然是可以达到的。
于是我们(O(n))枚举一下两个串的位置对应关系,(O(n))求一下总距离即可。
时间复杂度(O(n^2)).
代码
#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define riterator reverse_iterator
using namespace std;
inline int read()
{
int x = 0,f = 1; char ch = getchar();
for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
return x*f;
}
const int N = 5000;
char a[N+3],b[N+3];
int ta[N+3],tb[N+3];
int wa[3*N+7],wb[3*N+7];
int n,m1,m2;
int get_ta(int x) {return x>m1?n:ta[x];}
int get_tb(int x) {return x>m2?n:tb[x];}
int main()
{
scanf("%d%s%s",&n,a+1,b+1);
if(a[1]=='1') {ta[++m1] = 0;} for(int i=2; i<=n; i++) if(a[i]!=a[i-1]) {ta[++m1] = i-1;} if(a[n]=='1') {ta[++m1] = n;}
if(b[1]=='1') {tb[++m2] = 0;} for(int i=2; i<=n; i++) if(b[i]!=b[i-1]) {tb[++m2] = i-1;} if(b[n]=='1') {tb[++m2] = n;}
for(int i=m2+1; i<=m2+m1; i++) wa[i] = ta[i-m2];
for(int i=1; i<=m2; i++) wa[i] = 0;
for(int i=m2+m1+1; i<=m2+m1+m2; i++) wa[i] = n;
// printf("wa: "); for(int i=1; i<=m2+m1+m2; i++) printf("%d ",wa[i]); puts("");
int ans = 1e9;
for(int i=0; i<=m1+m2; i+=2)
{
for(int j=1; j<=m2; j++) {wb[i+j] = tb[j];}
for(int j=1; j<=i; j++) {wb[j] = 0;}
for(int j=i+m2+1; j<=m1+m2+m2; j++) {wb[j] = n;}
int cur = 0;
for(int j=1; j<=m1+m2+m2; j++) {cur += abs(wa[j]-wb[j]);}
ans = min(ans,cur);
}
printf("%d
",ans);
return 0;
}