Codeforces Round #759 (Div. 2) D 结论 求逆序数的个数

题目

给你一个长度为N 的数组 ai
给定一种操作
你可以选择3个下标 i j k
使得ai aj ak 的相对顺序改变成 ak ai aj
求能否通过这个操作使得原数组呈升序。

题解思路

当 i j k 都不同的时候,这个操作可以减少偶数倍的逆序数。
当存在两个相同的数的时候,就有点神奇了,他可以让其中那个不同的数任意走到其中某个位置,这样就可以不断选择这两个数,使得另一个数归位。
总结
当存在两个相同的数的时候,一定可以,当都不同的时候,必须满足逆序数为偶数倍才能操作出来。
求逆序数的个数的两种方法,树状数组,和归并排序。
写了树状数组的

AC代码
#include 
//#include 
//priority_queue
#define PII pair<int,int>
#define ll long long

using namespace std;

const  int  INF =  0x3f3f3f3f;
const  int  N =  500100;
int n ;
int tee[N] ;
int a[N] ; 
int lowbit(int x )
{
    return x&(-x) ; 
}
void add(int x )
{
    for ( ; x <= n ; x += lowbit(x) )
    {
        tee[x] += 1 ;
    }
}
int sum(int x )
{
    int res = 0 ;
    for ( ; x ; x -= lowbit(x) )
        res += tee[x] ; 
    return res ; 
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T ;
    cin >> T ;
    while ( T -- )
    {
        unordered_map <int , int > mp ; 
        int  falg = 1 ;
        cin >> n ; 
        for (int i = 1 ; i <= n ; i++ )
            cin >> a[i] , tee[i] = 0 , mp[a[i]]++ ;
        for (int i = 1 ; i <= n ; i++ )
        {
            if (mp[a[i]] > 1 )
                falg = 0 ; 
        }
        if (!falg)
        {
            cout << "YES\n" ;
            continue;
        }
        long long  ans = 0 ; 
        for (int i = 1 ; i <= n ; i++ )
        {
            add(a[i]) ; 
            //cout << sum(n) << " " << sum(a[i]) << "\n" ; 
            ans += sum(n) - sum(a[i]) ; 
        }
        //cout << ans << "\n" ; 
        if ( ans %  2 == 0 )
            cout << "YES\n" ;
        else
            cout << "NO\n" ; 
    }
    return 0 ;
}

归并排序


你可能感兴趣的:(巧妙的数据结构,思维,算法)