poj2299 - Ultra-QuickSort (求逆序数)

 题意:给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列。

我们需要知道:逆序数 = 在只允许相邻两个元素交换的条件下,得到有序序列的交换次数

所以我们需要求数列的逆序数,O(N*N)的算法肯定会超时的,

所有我们寻求较为高效的排序方法,归并排序就是充分利用分治法的而提高效率的排序方法。

归并排序:

#include <cstdio>
#define M  500005
int n , s[M];
long long ans;
void move(int l, int mid, int r)
{
    int len = r-l+1;
    int *a = new int[len+2];
    int li = l, ri = mid+1, i = 1;
    for(; li<=mid&&ri<=r;)
        if(s[li]<=s[ri]) a[i++] = s[li++];
        else
        {
            a[i++] = s[ri++];
            ans+=(mid-l+1-li+l);
        }
    while(li<=mid) a[i++] = s[li++];
    while(ri<=r) a[i++] = s[ri++];
    for(int j = 1; j <= len; ++j)
        s[j+l-1] = a[j];
    delete a;
}
void merge(int l, int r)
{
    if(l>=r) return;
    int mid = l+(r-l)/2;
    merge(l,mid);
    merge(mid+1,r);
    move(l, mid, r);
}
int main ()
{
    while(scanf("%d",&n), n)
    {
        for(int i = 1; i <= n; ++i)
            scanf("%d",&s[i]);
        ans = 0;
        merge(1,n);
        printf("%I64d\n",ans);
    }
    return 0;
}


我们还可以用树状数组来求其逆序数。
树状数组:

如果第一次接触树状数组的,可以看参考http://blog.csdn.net/q573290534/article/details/6664902

离散化+树状数组,====>求逆序数。

思路:把离散化的数组【9 1 0 5 4】==>【 5 2 1 4 3】逆序更新状态即可,

例如

1、查找以3开头的逆序数,把 就是查找已经插入的比3小的所有数字的个数。然后把3插入到数组【0】

2、查找以4开头的逆序数,更新4【1】

3、查找以1开头的逆序数,更新1【0】

4、。。。2。。。。。【1】

5、。。。5。。。。。【4】

最后答案就是【1+1+4 = 6 】

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 500005
#define lowbit(x) x&-x
struct Node{
    int v, x;
};
Node a[M];
int n, r[M], tree[M];
int comp(const Node p, const Node q) { return p.v<q.v; }
void update(int x)
{
    while(x<=n)
    {
        tree[x]+=1;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ret = 0;
    while(x>0)
    {
        ret+=tree[x];
        x-=lowbit(x);
    }
    return ret;
}
int main ()
{
    int t;
    while(scanf("%d",&n), n)
    {
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d",&t);
            a[i].v = t;
            a[i].x = i;
        }
        sort(a+1,a+1+n,comp);
        for(int i = 1; i <= n; ++i)
            r[a[i].x] = i;

        long long ans = 0;
        memset(tree,0,sizeof(tree));
        for(int i = n; i >= 1; i--)
        {
            ans+=sum(r[i]);
            update(r[i]);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}




posted on 2013-07-28 15:14  Primo...  阅读(159)  评论(0编辑  收藏  举报