ENCDEC8- Editorial

PROBLEM LINK:

Practice
Encoding December 2020

Author: Akash Kumar Bhagat
Tester: Arnab Chanda
Editorialist: Akash Kumar Bhagat

DIFFICULTY:

Medium

PREREQUISITES:

Maths, Divide and Conquer

PROBLEM:

You are given an array of numbers A of length N containing distinct integers from the range [1, N]. If we have 2 different sets of N numbers and we connect the i^{th} number from the first to the number i in another set, then count the number of intersections.

EXPLANATION:

This is the typical question of divide and conquer algorithm which is also referred to as the Inversion Problem. One of the way to solve os using merge sort approach and repeatedly divide the array in half until the base case is reached

We can create a function that counts the number of inversions when two halves of the array are merged, create two indices i and j, i is the index for the first half and j is an index of the second half. if a[i] is greater than a[j], then there are (mid – i) inversions. because left and right subarrays are sorted, so all the remaining elements in left-subarray (a[i+1], a[i+2] … a[mid]) will be greater than a[j].

Create a recursive function to divide the array into halves and find the answer by summing the number of inversions is the first half, number of inversion in the second half and the number of inversions by merging the two. The base case of recursion is when there is only one element in the given half.

You can refer to this article

TIME COMPLEXITY: O(n \log_2 n)

SOLUTIONS:

Python 3.7

def Sort_n_Count(arr):
    n=len(arr)
    if(n==1):
        return arr,0
    count=0
    temp1,x=Sort_n_Count(arr[:n//2])
    temp2,y=Sort_n_Count(arr[n//2:])
    count+=x+y
 
    i,j=0,0
    len1=n//2;len2=n-n//2
    sorted_array=[]
    while(i!=len1 and  j!=len2):
        if(temp1[i]<=temp2[j]):
            sorted_array.append(temp1[i])
            i+=1
        else:
            sorted_array.append(temp2[j])
            j+=1
            count+=len1-i
 
    while(i!=len1):
        sorted_array.append(temp1[i])
        i+=1
    while(j!=len2):
        sorted_array.append(temp2[j])
        j+=1
 
    return sorted_array,count
 
for i in range(int(input())):
    n,x=map(int,input().split())
    a=[int(i) for i in input().split()]
    print(2*x*Sort_n_Count(a)[1])

CPP
#include <bits/stdc++.h>
#define ll               long long int
#define ull              unsigned long long int
#define ld               long double
#define F(i,a,n)         for(long long int i=a;i<n;i++)
#define FO(i,a,n)        for(long long int i=n-1;i>=a;i--)
#define fast()           ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl             "\n"
#define M                998244353
#define pb(i)            push_back(i)
#define len(s)           s.length()
#define mp               make_pair
#define ss               second
#define ff               first
#define vll              vector<long long int>
#define vpair            vector<pair<long long int,long long int>>
#define MAX              100000
#define tolernace        1e-10
 
using namespace std;
 
//*******************************************************************
 
 
void input()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
}
 
 
ll power(ll a, ll b)
{
    ll ans = 1;
 
    while (b > 0)
    {
        if (b & 1)
        {
            ans = ans * a;
        }
        a = a * a;
        b >>= 1;
    }
    return ans;
}
 
 
ll gcd(ll a, ll b)
{
    if (b == 0)
        return a;
    return gcd(b, a % b);
 
}
 
//********************************************************************
 
ll merge(ll arr[], ll temp[], ll left, ll mid, ll right)
{
    ll inv_count = 0;
 
    ll i = left; /* i is index for left subarray*/
    ll j = mid;  /* i is index for right subarray*/
    ll k = left; /* i is index for resultant merged subarray*/
    while ((i <= mid - 1) && (j <= right))
    {
        if (arr[i] <= arr[j])
            temp[k++] = arr[i++];
        else
        {
            temp[k++] = arr[j++];
 
            /* this is tricky -- see above explanation/
              diagram for merge()*/
            inv_count = inv_count + (mid - i);
        }
    }
 
    /* Copy the remaining elements of left subarray
     (if there are any) to temp*/
    while (i <= mid - 1)
        temp[k++] = arr[i++];
 
    /* Copy the remaining elements of right subarray
     (if there are any) to temp*/
    while (j <= right)
        temp[k++] = arr[j++];
 
    /*Copy back the merged elements to original array*/
    for (i = left; i <= right; i++)
        arr[i] = temp[i];
 
    return inv_count;
}
 
 
ll _mergeSort(ll arr[], ll temp[], ll left, ll right)
{
    ll mid, inv_count = 0;
 
    if (right > left)
    {
        mid = (right + left) / 2;
 
 
        inv_count  = _mergeSort(arr, temp, left, mid);
        inv_count += _mergeSort(arr, temp, mid + 1, right);
 
 
        inv_count += merge(arr, temp, left, mid + 1, right);
    }
 
    return inv_count;
}
 
ll countSwaps(ll arr[], ll n)
{
    ll temp[n];
    return _mergeSort(arr, temp, 0, n - 1);
}
 
void solve()
{
    ll n, k = 1, x;
    cin >> n >> x;
 
    ll a[n];
    F(i, 0, n)
    {
        cin >> a[i];
    }
 
    cout << countSwaps(a, n) * 2 * x;
}
 
//*******************************************************************
 
 
int main()
{
    fast()
    input();
 
    // ll x = 1;
 
    int t = 1, i = 1;
    cin >> t;
 
    while (t--)
    {
        solve();
        cout << endl;
    }
 
}
 
 
 
 
 
//******************************************************************* 

Fenwick tree
#include<bits/stdc++.h>
using namespace std ;
 
#define ll              long long 
#define pb              push_back
#define all(v)          v.begin(),v.end()
#define sz(a)           (ll)a.size()
#define F               first
#define S               second
#define INF             2000000000000000000
#define popcount(x)     __builtin_popcountll(x)
#define pll             pair<ll,ll> 
#define pii             pair<int,int>
#define ld              long double
 
const int M = 1000000007;
const int MM = 998244353;
const long double PI = acos(-1);
 
template<typename T, typename U> static inline void amin(T &x, U y){ if(y<x) x=y; }
template<typename T, typename U> static inline void amax(T &x, U y){ if(x<y) x=y; }
template<typename T, typename U> ostream& operator<<(ostream &os, const pair<T, U> &p)
{ 
    return os<<'('<<p.F<< ","<<p.S<<')'; 
}
 
const int N = 100005;
 
template<typename T=long long>
struct fenwick {
    T a[N],bit[N];
    int n;
    fenwick() 
    {
        for(int i=1;i<=N-2;++i)
            a[i] = T(0),bit[i] = T(0);
    }
    void build(int n_)
    {
        n = n_;
        for(int i=1;i<=n;++i)
            bit[i] = 0;
    }
    void update(int j,T val)
    {
        for(;j<=n;j+=j&-j)
            bit[j] += val;
    }
    T get(int r)
    {
        T u = 0;
        for(;r;r-=r&-r)
            u += bit[r]; 
        return u;
    }
    T query(int l, int r)
    {
        return get(r)-get(l-1);
    }
};
fenwick<ll> fenw;
// call fenw.build(n);
 
int _runtimeTerror_()
{
    int n;
    ll x;
    ll ans = 0;
    cin>>n>>x;
    fenw.build(n);
    for(int i=1;i<=n;++i)
    {
        int x;
        cin>>x;
        ans += fenw.query(x+1,n);
        fenw.update(x,1);
    }
    ans *= 2*x;
    cout<<ans<<"\n";
    return 0;
}
 
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    #ifdef runSieve
        sieve();
    #endif
    #ifdef NCR
        initialize();
    #endif
    int TESTS=1;
    cin>>TESTS;
    while(TESTS--)
        _runtimeTerror_();
    return 0;
}

SOLUTION CREDIT

CPP → @horcrux903
Fenwick Tree → @anshugarg12

Hope you have enjoyed Encoding December 2020, we are eager to know your approach to the problem. :blush::blush::blush:

1 Like