求排列的逆序数

博客围绕求1到n排列的逆序数展开,介绍了逆序数概念,指出逆序数越大与原始排列差异度越大。给出求解注意点,需利用二分归并排序算法(分治),结果用long long存储,还附上了相应的C语言代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

openjudge011

题目:

一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。

现给定1,2,…,n的一个排列,求它的逆序数。

注意点:

1. 利用二分归并排序算法(分治);
2. 注意结果可能超过int的范围,需要用long long存储。

样例输入:

6
2 6 3 4 5 1

输出:

8

⭐用归并排序,注意数组的范围。

#include<stdio.h>
long long a[100001];
long long b[100001];
long long n;
long long count=0;//计数 
void M(long long a[],int start,int mid,int end,long long b[])//降序 
{
    int r=0;
    int pa=start;
    int pb=mid+1;
     
        while(pa<=mid&&pb<=end)
        {
            if(a[pa]>=a[pb])
            {
                b[r++]=a[pa++];
                count=count+end-pb+1;
            }
              
            else
            {
                b[r++]=a[pb++];
                
            }
              
        }
        while(pa<=mid)
           b[r++]=a[pa++];
        while(pb<=end)
           b[r++]=a[pb++];
    
    for(int i=0;i<end-start+1;i++)
       a[start+i]=b[i];
    
}
void Msort(long long a[],int start,int end,long long b[])
{
    if(start<end)
    {
        int mid=start+(end-start)/2;
        Msort(a,start,mid,b); 
        Msort(a,mid+1,end,b);
        M(a,start,mid,end,b);
    }
    
}
int main()
{    
    scanf("%lld",&n);
    for(long long i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);
    }
    Msort(a,0,n-1,b);
    printf("%lld",count);
    return 0;
}

### 计算排列逆序数的算法 #### 归并排序基础上计算逆序数的方法 在二路归并排序的过程中可以顺便统计逆序数。当处理两个子数组A和B时,如果来自右半部分(即B)的一个元素被先放入临时数组,则说明此元素与左半部分剩余未处理的所有元素构成逆序对[^1]。 对于给定序列`arr=[2, 6, 3, 4, 5, 1]`,其逆序数可以通过修改后的归并排序来获得: ```python def merge_count_split_inv(arr_left, arr_right): result = [] count = 0 i, j = 0, 0 while i < len(arr_left) and j < len(arr_right): if arr_left[i] <= arr_right[j]: result.append(arr_left[i]) i += 1 else: result.append(arr_right[j]) count += (len(arr_left)-i) j += 1 result.extend(arr_left[i:]) result.extend(arr_right[j:]) return result, count def sort_and_count_inversions(array): length = len(array) if length <= 1 or not array: return array, 0 mid_point = length // 2 sorted_first_half, first_half_invs = sort_and_count_inversions(array[:mid_point]) sorted_second_half, second_half_invs = sort_and_count_inversions(array[mid_point:]) merged_array, split_invs = merge_count_split_inv(sorted_first_half, sorted_second_half) total_inversions = first_half_invs + second_half_invs + split_invs return merged_array, total_inversions if __name__ == "__main__": test_arr = [2, 6, 3, 4, 5, 1] _, inversions_num = sort_and_count_inversions(test_arr) print(f"The number of inversions is {inversions_num}.") ``` 上述代码实现了基于归并排序思想的逆序数计数函数。通过递归地分割输入列表直到单个元素,之后逐步合并这些片段的同时累加各层产生的逆序数量,最终得到整个列表中的总逆序数目[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值