#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// Helper to find median of three and swap pivot to the end
int medianOfThree(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
{
    int mid = low + (high - low) / 2;

    comp_count++;
    if (nums[low] > nums[mid])
    {
        swap(nums[low], nums[mid]);
        move_count += 3;
    }
    comp_count++;
    if (nums[low] > nums[high])
    {
        swap(nums[low], nums[high]);
        move_count += 3;
    }
    comp_count++;
    if (nums[mid] > nums[high])
    {
        swap(nums[mid], nums[high]);
        move_count += 3;
    }
    
    // Now nums[low] <= nums[mid] <= nums[high]
    // Pivot is nums[mid], but we swap it with nums[high-1] to use in partition
    // The partition logic will ignore the already sorted nums[low] and nums[high]
    swap(nums[mid], nums[high]); // Move pivot to the end
    move_count += 3;
    return nums[high];
}


int partition_optimized(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
{
    int pivot = medianOfThree(nums, low, high, comp_count, move_count);
    int i = (low - 1);

    for (int j = low; j <= high - 1; j++)
    {
        comp_count++;
        if (nums[j] < pivot)
        {
            i++;
            swap(nums[i], nums[j]);
            move_count += 3;
        }
    }
    swap(nums[i + 1], nums[high]);
    move_count += 3;
    return (i + 1);
}

void quickSortOptimizedHelper(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
{
    if (low < high)
    {
        int pi = partition_optimized(nums, low, high, comp_count, move_count);
        quickSortOptimizedHelper(nums, low, pi - 1, comp_count, move_count);
        quickSortOptimizedHelper(nums, pi + 1, high, comp_count, move_count);
    }
}

/*
 * function   : implement quick sort with median-of-three pivot selection
 * param nums : the vector to be sorted
 * param comp_count : count of comparisons
 * param move_count : count of moves
 * return     : ---
 */
void QuickSortOptimized(vector<int> &nums, long long &comp_count, long long &move_count)
{
    if (nums.empty()) return;
    quickSortOptimizedHelper(nums, 0, nums.size() - 1, comp_count, move_count);
}
