给定一个长度为
n
n
n的数组
a
a
a,进行若干次操作,使得对于
∀
1
≤
i
<
n
\forall_{1\le i < n}
∀1≤i<n,
a
i
a_i
ai和
a
i
+
1
a_{i+1}
ai+1的奇偶性都不相同。
即相邻两个元素一定有一个是奇数且另一个是偶数。
操作:交换任意两个相邻元素( s w a p ( a i , a i + 1 ) swap(a_i,a_{i+1}) swap(ai,ai+1))。
问最小的操作次数是多少。
首先,对于数组 a a a,只需要关注 a i a_i ai的奇偶性,而不需要关注每个元素的具体值。
对于任意一个数列,如果可以满足条件的话,奇偶性一定为:101010101...
或者01010101...
。
则奇数的个数
c
n
t
1
cnt1
cnt1和偶数的个数
c
n
t
2
cnt2
cnt2差值不超过
1
1
1,否则一定无解。
如果
c
n
t
1
=
c
n
t
2
+
1
cnt1=cnt2+1
cnt1=cnt2+1的话,最终数列的奇偶性一定为101010...01
。
如果
c
n
t
2
=
c
n
t
1
+
1
cnt2=cnt1+1
cnt2=cnt1+1的话,最终数列的奇偶性一定为010101...10
。
如果
c
n
t
2
=
c
n
t
1
cnt2=cnt1
cnt2=cnt1的话,有两种可能性:101010...0
和010101...1
。
如果我只关注奇数需要的排的位置的话,奇数排好之后偶数就已经排好了。
对于数组
A
A
A:00011
(需要转成01010
),“将
A
3
A_3
A3移动到
A
1
A_1
A1”和“将
A
4
A_4
A4移动到
A
1
A_1
A1”最终花费是相同的的。
如果移动
A
3
A_3
A3的话,
A
4
A_4
A4还需要移动到
A
3
A_3
A3。
所以只需要枚举奇数起始的位置和奇数需要放的位置,可以直接用双指针来进行这个操作。
#include <bits/stdc++.h>
using namespace std;
int T, n;
int main() {
cin >> T;
while (T--) {
cin >> n;
int cnt1 = 0, cnt2 = 0; // 记录奇数和偶数的个数
int a1 = 1, r1 = 0; // 奇数在奇数位置
int a2 = 2, r2 = 0; // 奇数在偶数位置
for (int i = 1; i <= n; i++) {
int tmp;
cin >> tmp;
if (tmp & 1) {
cnt1++;
r1 += abs(a1 - i);
r2 += abs(a2 - i);
a1 += 2, a2 += 2; // 奇数应该在的位置(向后移动两位)
} else
cnt2++;
}
if (cnt1 == cnt2 + 1)
cout << r1 << endl;
else if (cnt2 == cnt1 + 1)
cout << r2 << endl;
else if (cnt2 == cnt1)
cout << min(r1, r2) << endl;
else
cout << -1 << endl;
}
return 0;
}