当前位置: 首页 > 工具软件 > Places > 使用案例 >

CF1556B - Take Your Places!

白学
2023-12-01

题目链接

题意

给定一个长度为 n n n的数组 a a a,进行若干次操作,使得对于 ∀ 1 ≤ i < n \forall_{1\le i < n} 1i<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...0010101...1

如果我只关注奇数需要的排的位置的话,奇数排好之后偶数就已经排好了。

对于数组 A A A00011(需要转成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

所以只需要枚举奇数起始的位置奇数需要放的位置,可以直接用双指针来进行这个操作。

AC的代码

#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;
}

 类似资料:

相关阅读

相关文章

相关问答