POJ 2299 Ultra-QuickSort

题目链接:POJ 2299 Ultra-QuickSort

乍一看是冒泡排序,不过用冒泡排序会超时。

仔细想想其实就是求逆序对总数。

用分治法(归并排序改一下)可以做。

还可以用树状数组做,不过0 ≤ a[i] ≤ 999,999,999范围太大了,这里用到了离散化的思想,下面引用别人的解释:离散化,是数据范围太大是所借用的利器,举个例子,有四个数99999999 1 123 1583 数据范围太大,而树状数组中的c数组开的范围是数据的范围,这时候就需要离散化,把四个数一次标号为1 2 3 4(即第一个数,第二个数。。。),按键值排序之后 依次为2 3 4 1(即从小到大排序为第二个数,第三个数。。。),所以,第二个数是最小的,即f[2]=1,f[3]=2,f[4]=3,f[1]=4,也就是把键值变为了1~n,相对大小还是不变的,即4 1 2 3。比如要求原来四个数的逆序数总和,现在就是求4 1 2 3的逆序数总和,大大节省了空间压力(树状数组的长度是数据范围)。


两份代码都是407 ms,甚是诡异。

#include <iostream>
#include <stdio.h>
#include <cstring>

using namespace std;

const int MAX_N = 500000 + 1000;
int n;
int a[MAX_N],t[MAX_N];
//__int64 cnt;
long long cnt;

void merge_sort(int *A,int x,int y,int *T)            //左开右闭
{
     if(y - x > 1)
     {
         int m = x + (y - x) / 2;                     //划分
         int p = x,q = m,i = x;
         merge_sort(A,x,m,T);                        //递归求解
         merge_sort(A,m,y,T);                        //递归求解
         while(p < m || q < y)
         {
             if(q >= y || (p < m && A[p] <= A[q]))  //从左半数组复制到临时空间
                T[i++] = A[p++];
             else                                  //从右半数组复制到临时空间
             {
                 T[i++] = A[q++];
                 cnt += m - p;
             }
         }
         for(i = x;i < y;i++)
            A[i] = T[i];
     }
}
int main()
{
    while(scanf("%d",&n) != EOF,n)
    {
        cnt = 0;
        memset(a,0,sizeof(a));
        memset(t,0,sizeof(t));
        for(int i = 0;i < n;i++)
            scanf("%d",&a[i]);
        merge_sort(a,0,n,t);
        //printf("%I64d\n",cnt);
        printf("%lld\n",cnt);
    }
    return 0;
}

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>

using namespace std;

struct Node
{
    int val,i;
};

const int MAX_N = 500000 + 1000;
int n;
int arr[MAX_N];
int num[MAX_N];
Node node[MAX_N];
long long cnt;

bool cmp(Node a,Node b)
{
    return a.val < b.val;
}
int lowbit(int i)
{
    return i & (-i);
}
int sum(int i)
{
    int ans = 0;
    while(i > 0)
    {
        ans += num[i];
        i -= lowbit(i);
    }
    return ans;
}
void add(int i,int val)
{
    while(i <= n)
    {
        num[i] += val;
        i += lowbit(i);
    }
}
int main()
{
    while(scanf("%d",&n),n)
    {
        memset(num,0,sizeof(num));
        cnt = 0;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&node[i].val);
            node[i].i = i;
        }
        sort(node + 1,node + 1 + n,cmp);
        arr[node[1].i] = 1;
        for(int i = 2;i <= n;i++)
        {
            if(node[i].val == node[i - 1].val)
                arr[node[i].i] = i - 1;
            else
                arr[node[i].i] = i;
        }
        for(int i = 1;i <= n;i++)
        {
            add(arr[i],1);
            cnt += sum(n) - sum(arr[i]);
        }
        printf("%lld\n",cnt);
    }
    return 0;
}


你可能感兴趣的:(POJ 2299 Ultra-QuickSort)