【贪心,思维】CF1700F Puzzle

· · 题解

Description

给出两个 2 \times n 的 01 矩阵 A,B,每次操作可以交换 A 中任意两个相邻位置的值,求使得 A = B 的最小操作次数。

# Solution 我们首先考虑 $1 \times n$ 矩阵的情况。 观察样例,不难发现结论:此时使得 $1 \times n$ 矩阵 $A=B$ 的最小操作次数即为 $$\sum_{i=1}^n |{\rm sum}A_i-{\rm sum}B_i|$$ 其中 ${\rm sum}A_i= \sum\limits_{j=1}^i A_j$,${\rm sum}B_i$ 同理,对于上式的证明留作读者练习。 接下来考虑拓展到 $2 \times n$ 矩阵的情况,可以发现,无非就是对于原来单独的两行,增加了一个上下交换操作。 我们以将第一行的 $1$ 转移下去的上下交换操作为例,注意到,这会使第一行 $A-B$ 的前缀和减 $1$,而第二行则会加 $1$。 由于答案取绝对值,不难想到,若两行 $A-B$ 的前缀和同号,那么交换操作一定是没有意义的,不会使答案变优。 但是,若它们异号,我们则可以移动 $\min\{|{\rm sum}A_{i,1}-{\rm sum}B_{i,1}|,|{\rm sum}A_{i,2}-{\rm sum}B_{i,2}\}|$ 个 $1$,使得其中之一变为 $0$。这样可以将原来 $2$ 次的左右交换操作,优化为 $1$ 次的上下交换操作。 值得一提的是,尽管这样的移动具有后效性,但可以分析出来,它并不会使我们的答案变劣,因此这是合法的贪心做法。 至此我们就在 $\mathcal O(n)$ 的时间复杂度下完成了本题。 # Code ```cpp #include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=2e5+5; int n,a[2][N],b[2][N]; LL sum,Ans; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[0][i]),sum+=a[0][i]; for (int i=1;i<=n;i++) scanf("%d",&a[1][i]),sum+=a[1][i]; for (int i=1;i<=n;i++) scanf("%d",&b[0][i]),sum-=b[0][i]; for (int i=1;i<=n;i++) scanf("%d",&b[1][i]),sum-=b[1][i]; if (sum) { printf("-1"); return 0; } LL s0=0,s1=0; for (int i=1;i<=n;i++) { s0+=a[0][i]-b[0][i],s1+=a[1][i]-b[1][i]; if (s0<0 && s1>0) { int nm=min(-s0,s1);Ans+=nm;s0+=nm,s1-=nm; } else if (s0>0 && s1<0) { int nm=min(s0,-s1);Ans+=nm;s0-=nm,s1+=nm; } Ans+=abs(s0)+abs(s1); } printf("%lld",Ans); return 0; } ```