Codeforces Round #732 Div2 C. AquaMoon and Strange Sort

C. AquaMoon and Strange Sort

原题链接

对于最终所有数字的状态依然是 r i g h t right right 这个条件我们可以知道,每个数字只能被操作偶数次,也就是在奇数下标的数字最终只能停在奇数下标,偶数下标的数字最终只能停在偶数下标。所以,最终状态是 r i g h t right right l e f t left left 只和最初和最终的位置有关,一个数字中间怎么被交换的根本就不用在意,而且相邻交换又没有其他限制,也就是一个数字最终要停在任何一个位置都是可以通过交换实现的(只要不是一个位置放两个数字),再说的明白点,就是可以通过相邻交换形成全排列中的任意一种。

那么根据我们上述讨论出来的结论,我们现在来讨论如何判断这个序列是否符合条件。因为数字不唯一,我们现在考虑某一种数字最终是否能够满足条件,最终每一种数字都能满足条件即输出 Y E S YES YES
某一种数字满足条件即满足以下两个条件:
①位置正确,由于最终序列要递增,某一种数字只能放在某一个区间内。
②状态正确:即最终状态都为 r i g h t right right
那么对于这一种数字我们先考虑位置正确:很显然,我们用排序后再二分的方式,可以找到这一种数字的范围必须放在 [ i d x 1 , i d x 2 ] [idx1,idx2] [idx1,idx2] 之间。
然后我们再考虑状态正确:我们这里假设这一种数字中有 x x x 个下标为奇数, y y y 个下标为偶数。那么我们要让这 x + y x+y x+y 个数字的状态都正确,也就是 x x x 个数字最终必须放在下标为奇数的地方, y y y 个数字最终必须放在下标为偶数的地方。然而我们在这之前要保证位置正确,也就是这 x + y x + y x+y 个数字只能放在 [ i d x 1 , i d x 2 ] [idx1, idx2] [idx1,idx2] 这个下标区间内,那么只要这个区间内有 x x x 个奇数下标, y y y 个偶数下标,就又保证了位置正确,最终状态也都为 r i g h t right right ,这种数字才能被正确摆放。(注意:不要考虑是否能够摆放成这种情况,上述已经讨论过,根据相邻交换,可以将序列摆放成其全排列中的任一一种)

c o d e code code

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 2;

int g[N][2];
int n;
int a[N];

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int T;
    scanf("%d", &T);
    while(T--) {
        bool ok = true;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            g[a[i]][i & 1]++;
        }
        sort(a + 1, a + 1 + n);
        for (int i = 1; i <= n; ++i) {
            int idx1 = lower_bound(a + 1, a + 1 + n, a[i]) - a;
            int idx2 = upper_bound(a + 1, a + 1 + n, a[i]) - a - 1;
            int len = idx2 - idx1 + 1, odd, even;
            if (len & 1) {
                if (idx1 & 1) {
                    odd = len / 2 + 1;
                    even = len / 2;
                }
                else {
                    even = len / 2 + 1;
                    odd = len / 2;
                }
            }
            else {
                odd = even = len / 2;
            }
            if (even != g[a[i]][0] || odd != g[a[i]][1]) {
                ok = false;
                break;
            }
        }
        if (ok) {
            printf("YES\n");
        }
        else {
            printf("NO\n");
        }
        for (int i = 1; i <= n; ++i) g[a[i]][0] = g[a[i]][1] = 0;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值