【CodeForces】1585D Yet Another Sorting Problem题解

题目大意

给定一个 n n n个数的数组 a a a

每次可以选择三个数 a i , a j , a k ( 1 ≤ i , j , k ≤ n ) a_i, a_j, a_k(1 \le i,j,k \le n) ai,aj,ak(1i,j,kn),使得 a i a_i ai a j a_j aj原来的位置, a j a_j aj a k a_k ak原来的位置, a k a_k ak a i a_i ai原来的位置。( 1 ≤ n , a i ≤ 1 0 5 1 \le n, a_i \le 10^5 1n,ai105)

问是否可以通过这种方式使得数组变成升序有序数组

题目地址

思路

首先需要知道这么一个规律,交换一个序列中两个不同的数会使这个序列的逆序对数改变奇数个

而题目的这种操作就像与连续进行两次操作(交换 a i , a j a_i, a_j ai,aj,然后交换 a j , a k a_j ,a_k aj,ak),那么显然逆序数的变换是偶数个

所以,只要原序列的逆序数是偶数,那么肯定可以做到。

当然还有一种特殊情况:

有两个相同的数,那么我们可以把这两个数作为媒介,可以等价于随意交换任意两个数,所以此时无论如何都能交换成功。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxN = 5e5 + 7;

int T, n, a[maxN], b[maxN], c[maxN];

bool cmp(int x, int y)
{
    return x < y;
}

inline void Add(int x, int k)
{
    for(; x <= n; x += x&(-x))
        c[x] += k;
}

inline int GetSum(int x)
{
    int ans = 0;
    for(; x; x -= x&(-x))
        ans += c[x];
    return ans;
}

int main()
{
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            b[i] = a[i];
        }
        sort(a + 1, a + 1 + n, cmp);
        int cnt = 0; bool mul = false;
        for(int i = 1; i <= n; ++i)
            if(a[i] == a[i - 1]) { //判断是否有重复
                mul = true;
                break;
            }
        if(mul)
            printf("YES\n");
        else  {
            int num = 0;
            memset(c, 0, sizeof c);
            for(int i = n; i > 0; i--) {
                num += GetSum(b[i] - 1);
                Add(b[i], 1);
            }
            if(num & 1)
                printf("NO\n");
            else
                printf("YES\n");
        }
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值