现在的位置: 首页 > 综合 > 正文

nyoj 117 逆序数(树状数组+离散化+sort结构体排序(注意!))

2018年04月26日 ⁄ 综合 ⁄ 共 2497字 ⁄ 字号 评论关闭
归并排序时间短

描述

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。

现在,给你一个N个元素的序列,请你判断出它的逆序数是多少。

比如 1 3 2 的逆序数就是1。

输入
第一行输入一个整数T表示测试数据的组数(1<=T<=5)
每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)
随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所有元素。

数据保证在多组测试数据中,多于10万个数的测试数据最多只有一组。

输出
输出该数列的逆序数
样例输入
2
2
1 1
3
1 3 2
样例输出
0
1
 
 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mav 1000005
int num[mav],rev[mav],n;
struct node
{
    int p,x;
}nodes[mav];
int cmp(node a,node b)
//注意这里,wrong了很多次,记得当值相等的时候序号的比较
{
    if(a.p!=b.p)
    return a.p<b.p;
    else return a.x<b.x;
}
int lowbit(int x)
{
    return x&(-x);
}
void add(int x)
{
    while(x<=n)
    {
        num[x]++;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int total=0;
    while(x>0)
    {
        total+=num[x];
        x-=lowbit(x);
    }
    return total;
}
int main()
{
    int x,cases,i;
    scanf("%d",&cases);
    while(cases--)
    {
        scanf("%d",&n);
        memset( num,0,sizeof( num ));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&nodes[i].p);
            nodes[i].x=i;
        }
        sort(nodes+1,nodes+n+1,cmp);
        for(i=1;i<=n;i++)
        {
            rev[nodes[i].x]=i;
        }
        long long int ss = 0;
        for(i = 1; i <=n; ++i )
        {
            add(rev[i]);
            ss +=(i-sum(rev[i]));
        }
        printf("%lld\n",ss);
    }
    return 0;
}
     

           

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mav 1000002
int num[mav],rev[mav],n;
struct node
{
    int p,x;
}nodes[mav];
int cmp(node a,node b)
{
    if(a.p!=b.p)
    return a.p<b.p;
    else return a.x<b.x;
}
int lowbit(int x)
{
    return x&(-x);
}
void add(int x)
{
    while(x<=n)
    {
        num[x]++;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int total=0;
    while(x)
    {
        total+=num[x];
        x-=lowbit(x);
    }
    return total;
}
int main()
{
    int x,cases,i;
    scanf("%d",&cases);
    while(cases--)
    {
        scanf("%d",&n);
        memset( num,0,sizeof(num));
        memset(rev,0,sizeof(rev));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x);
            nodes[i].p=x;
            nodes[i].x=i;
        }
        sort(nodes+1,nodes+n+1,cmp);
        for(i=1;i<=n;i++)
        {
            rev[nodes[i].x]=i;
        }
        long long int ss = 0;
        for(i = 1; i <=n; ++i )
        {
            add(rev[i]);
            ss +=(i-1-sum(rev[i]- 1));
        }
        printf("%lld\n",ss);
    }
    return 0;
}
                        

归并排序求逆序数

import java.util.Arrays;
import java.util.Scanner;
public class Main {
    static int a[]=new int[1000010];
    static int b[]=new int[1000010];
    static long sum=0;
    public static void merge(int a[],int begin,int end,int b[])
    {
    	if(begin==end)return ;
    	int mid=(begin+end)/2;
    	merge(a, begin, mid, b);
    	merge(a, mid+1, end, b);
    	int i=begin,j=mid+1,pos=begin;
    	while(i<=mid&&j<=end)
    	{
    		if(a[i]<=a[j])
    			b[pos++]=a[i++];
    		else {
				b[pos++]=a[j++];
				sum+=mid+1-i;
			}
    	}
    	while(i<=mid)
    	{
    		b[pos++]=a[i++];
    	}
    	while(j<=end)
    	{
    		b[pos++]=a[j++];
    	}
    	for(int k=begin;k<=end;k++)
    	{
    		a[k]=b[k];
    	}
    }
	public static void main(String[] args) {
	  Scanner scanner=new Scanner(System.in);
	  int cases=scanner.nextInt();
	  while(cases--!=0)
	  {
		  int number=scanner.nextInt();
		  Arrays.fill(a, 0);
		  Arrays.fill(b, 0);
		  sum=0;
		  for(int i=1;i<=number;i++)
		  {
			  a[i]=scanner.nextInt();
		  }
		  merge(a, 1, number, b);
		  System.out.println(sum);
	  }

	}

}

抱歉!评论已关闭.