A - Ultra-QuickSort OpenJ_Bailian - 2299(离散化求逆序对/归并排序)

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
9 1 0 5 4 ,

Ultra-QuickSort produces the output
0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input
The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 – the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.
Output
For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.
Sample Input
5
9
1
0
5
4
3
1
2
3
0
Sample Output
6
0

离散化求逆序对(排个序就离散化了,并不需要去重)

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

const ll maxn = 5e5 + 7;
ll a[maxn],c[maxn],b[maxn],n;
ll num[maxn],cnt;

ll query(ll x)
{
    return lower_bound(b + 1,b + 1 + n,x) - b;
}

ll lowbit(ll x)
{
    return x & (-x);
}

void add(ll x,ll v)
{
    while(x <= maxn)
    {
        c[x] += v;
        x += lowbit(x);
    }
}

ll sum(ll x)
{
    ll res = 0;
    while(x)
    {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

int main()
{
    while(~scanf("%lld",&n) && n)
    {
        cnt = 0;
        memset(c,0,sizeof(c));
        for(ll i = 1;i <= n;i++)
        {
            scanf("%lld",&a[i]);b[i] = a[i];
        }
        sort(b + 1,b + 1 + n);

        ll ans = 0;
        for(ll i = 1;i <= n;i++)
        {
            ll pos = query(a[i]);
            add(pos,1);
            ans += sum(500005) - sum(pos);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

归并排序求逆序对,个人感觉就是在归并排序的过程中,算出右半部分的数,在左边部分能组成多少个逆序对数。因为是分治,每个半块不会重复,然后递归的求解。

#include <cstdio>

const int maxn = 5e5 + 7;
typedef long long ll;
int a[maxn],b[maxn];

ll merge(int *a,int *b,int i,int j)
{
    if(i == j)return 0;
    ll ans = 0;
    int mid = (i + j) >> 1;
    ans += merge(a,b,i,mid);
    ans += merge(a,b,mid + 1,j);
    
    int p = i,q = mid + 1,k = i;
    while(p <= mid || q <= j)
    {
        if(p > mid || (q <= j && a[p] > a[q]))
        {
            b[k++] = a[q++];
            ans += mid - p + 1;//q在左半部分得到的逆序对数
        }
        else
        {
            b[k++] = a[p++];
        }
    }
    for(k = i;k <= j;k++)
        a[k] = b[k];
    return ans;
}

int main()
{
    int n;
    while(~scanf("%d",&n) && n)
    {
        for(int i = 0;i < n;i++)
        {
            scanf("%d",&a[i]);
        }
        printf("%lld\n",merge(a,b,0,n - 1));
    }
    return 0;
}

快速排序(QuickSort)是一种高效的排序算法,它的平均时间复杂度为O(nlogn)。它是通过将待排序数组分成两部分,其中一部分的所有元素都比另一部分的所有元素小,然后对这两部分分别进行递归排序,最终将整个数组排序。 以下是Java实现的快速排序代码: ```java public class QuickSort { public static void quickSort(int[] arr, int start, int end) { if (start < end) { int pivot = partition(arr, start, end); quickSort(arr, start, pivot - 1); quickSort(arr, pivot + 1, end); } } private static int partition(int[] arr, int start, int end) { int pivot = arr[end]; int i = start - 1; for (int j = start; j < end; j++) { if (arr[j] <= pivot) { i++; swap(arr, i, j); } } swap(arr, i + 1, end); return i + 1; } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void main(String[] args) { int[] arr = {5, 3, 8, 4, 2, 7, 1, 10}; quickSort(arr, 0, arr.length - 1); for (int i : arr) { System.out.print(i + " "); } } } ``` 在这个实现中,我们使用了递归来进行快速排序。首先,我们将数组分成两部分,然后对这两部分分别进行递归排序。在partition函数中,我们选择了数组的最后一个元素作为枢轴(pivot),并通过比较其他元素和枢轴的大小进行交换,将比枢轴小的元素放在枢轴的左边,比枢轴大的元素放在枢轴的右边。最后,我们将枢轴放在数组的正确位置上,并返回该位置。 在这个实现中,我们使用了swap函数来交换数组中的元素。我们也可以使用Java自带的Arrays.sort()函数来进行快速排序,它的实现也是基于快速排序算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值