Chinaunix首页 | 论坛 | 博客
  • 博客访问: 316968
  • 博文数量: 93
  • 博客积分: 2515
  • 博客等级: 少校
  • 技术积分: 1025
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-18 22:51
文章分类

全部博文(93)

文章存档

2010年(2)

2009年(26)

2008年(65)

我的朋友

分类: C/C++

2009-05-20 21:03:18

求逆序数的几种方法
分治法(合并排序时计算)

把数组 a 划分为 [first, (first+last)/2)(左)、[(first+last)/2, last)(右) 两部分
[first, last) 的逆序数 = 左半部分逆序数 + 右半部分逆序数 + 两数分别出现在左、card(pair(i, j) | i∈左 且 j∈右)

#include
#include

#define N 100

int a[N], b[N], n;

int Calc(int first, int last)
{
    if (first == last-1) return 0;
    int mid = (first+last)/2, i = first, j = mid, k = first,
        res = Calc(first, mid)+Calc(mid, last);
    while (i < mid && j < last)
    {
        if (a <= a[j]) b[k++] = a[i++], res += j-mid;
        else b[k++] = a[j++];
    }
    while (i < mid) b[k++] = a[i++], res += j-mid;
    while (j < last) b[k++] = a[j++];
    memcpy(a+first, b+first, sizeof(b[0])*(last-first));
    return res;
}

int main()
{
    int res = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%d", &a);
    printf("%d\n", Calc(0, n));
    return 0;
}

-----

线段树

对每一次输入的 t,计算以前输入的大于 t 的数的个数之和 s。∑s 即为结果
利用线段树,就能快速计算出任意的 s

输入的数的范围为 1~N(所以时间复杂度和前一种方法略有差别)

#include

#define N 100

int a[N*2-1];

void Inc(int root, int first, int last, int x)
{
    ++a[root];
    if (first == last-1) return;
    if (x < (first+last+1)/2) Inc(root*2+1, first, (first+last+1)/2, x);
    else Inc(root*2+2, (first+last+1)/2, last, x);
}

int Sum(int root, int first, int last, int x)
{
    if (first == last-1) return a[root];
    return (x < (first+last+1)/2 ? Sum(root*2+1, first, (first+last+1)/2, x) : 0)
        + Sum(root*2+2, (first+last+1)/2, last, x);
}

int main()
{
    int n, res = 0;
    for (scanf("%d", &n); n; --n)
    {
        int t;
        scanf("%d", &t);
        res += Sum(0, 1, N+1, t+1);
        Inc(0, 1, N+1, t);
    }
    printf("%d\n", res);
    return 0;
}

-----

树状数组

类似于线段树

输入的数的范围为 1~N

#include

#define N 100

int a[N+1];

void Inc(int x)
{
    for (; x <= N; x += (x^x-1)&x)
        ++a[x];
}

int Sum(int x)
{
    int res = 0;
    for (; x; x -= (x^x-1)&x)
        res += a[x];
    return res;
}

int main()
{
    int n, res = 0;
    for (scanf("%d", &n); n; --n)
    {
        int t;
        scanf("%d", &t);
        res += Sum(N-t);
        Inc(N-t+1);
    }
    printf("%d\n", res);
    return 0;
}
阅读(3090) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~