XidianOJ 1024 简单逆序对

题目描述

逆序对问题对于大家来说已经是非常熟悉的问题了,就是求i<j时,a[i] > a[j]的组数。现在请你求出一串数字中的逆序对的个数,需要注意的是,这些数字均在[0,9]之内。

输入

第一行输入T,表示有T组测试数据

对于每组数据,首先输入n,代表有n个数(0<n<=10^6)

接下来输入n个数,每个数都在[0,9]之内

输出

输出逆序对的个数,且对10^9+7取模

--正文

使用的是归并排序求逆序对,其实还有很多种

PS: 打10^9的时候老是不小心多打个0少打个0,WA了半天,诶

#include <stdio.h>

int a[1000001];
int tempa[1000001];
long long total = 0;
void merge(int left,int mid,int right){
    int endl = mid - 1,endr = right;
    int L = left,R = mid;
    int Tmp = left;
    int NumElements = right - left + 1;
    while (L<= endl && R <= endr) {
        if (a[L] <= a[R]) {
            tempa[Tmp++] = a[L++];
        }
        else {
            total += endl - L + 1;
            tempa[Tmp++] = a[R++];
        }
    }
    while (L<=endl){
        tempa[Tmp++] = a[L++];
    }
    while (R<=endr){
        tempa[Tmp++] = a[R++];
    }
    int i;
    for (i=0;i<=NumElements;i++,endr--){
        a[endr] = tempa[endr];
    }
}

void mergesort(int left,int right){
    int mid = (left + right) / 2;
    if (left < right){
        mergesort(left,mid);
        mergesort(mid+1,right);
        merge(left,mid+1,right);
    }
} 

int main() {
    int time,T;
    scanf("%d",&T);
    for (time=1;time<=T;time++){
        int n;
        scanf("%d",&n);
        int i;
        for (i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        total = 0;
        mergesort(1,n);
        printf("%lld\n",total % 1000000007);
    }

    return 0;
}
时间: 2024-10-26 02:43:06

XidianOJ 1024 简单逆序对的相关文章

剑指offer: 数组中的逆序对

1. 最简单的思路,对每个值,遍历与其逆序的数组对:但时间复杂度太高: 2. 归并排序的思路: 先将数组分隔成子数组,先统计出子数组内的逆序对的数目,然后统计两个相邻子数组之间的逆序对的数目: int InversePairsCore(int *data, int * copy, int start, int end) { //递归介绍条件,只剩一个元素 if(start==end) { copy[start]=data[start]; return 0; } int length=(end-s

【树状数组逆序对】USACO.2011JAN-Above the median

[题意] 给出一串数字,问中位数大于等于X的连续子串有几个.(这里如果有偶数个数,定义为偏大的那一个而非中间取平均) [思路] 下面的数据规模也小于原题,所以要改成__int64才行.没找到测试数据,自己编的几组.简单来说读入每个数,大于等于中位数设为1,小于设为-1,前i个数的和建立一个树状数组,求逆序对. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorit

hdu1394(线段树求逆序对)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 线段树功能:update:单点增减 query:区间求和 分析:如果是0到n-1的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少a[i],而增加n-1-a[i]的,所以每次变化为res+=n-a[i]-1-a[i]. #include<iostream> #include<cstdio> #include<cstring> #include<alg

归并排序求逆序对

归并排序求逆序对 by mps [1]什么是逆序对? 对于一个数列需要按从小到大排序,如果有ai,aj且满足ai>aj和i<j则ai,aj为一组逆序对 [2]如何求逆序对? 我们发现,我们可以暴力枚举i,j,然后逐一判断并累加答案即可,时间复杂度O(N2)        但是对于数据量大一点的题目,只有不断地TLE了→_→ [3]归并排序求逆序对 逆序对的定义(见[1])是一组本应该有序的序列中的逆序对,那么我们就想到了排序,但由于是要22匹配,我们又想到了归并排序 归并排序大致内容如下: 将

树状数组求逆序对:POJ 2299、3067

前几天开始看树状数组了,然后开始找题来刷. 首先是 POJ 2299 Ultra-QuickSort: http://poj.org/problem?id=2299 这题是指给你一个无序序列,只能交换相邻的两数使它有序,要你求出交换的次数.实质上就是求逆序对,网上有很多人说它的原理是冒泡排序,可以用归并排序来求出,但我一时间想不出它是如何和归并排序搭上边的(当初排序没学好啊~),只好用刚学过的树状数组来解决了.在POJ 1990中学到了如何在实际中应用上树状数组,没错,就是用个特殊的数组来记录即

剑指offer (36) 数组中的逆序对

题目:在数组中的两个数字如果前面一个数字大于后面一个数字,则这两个数字组成一个逆序对 题解分析: 首先应该想到很简单的一种解法,顺序遍历数组,对每个数,逐个比较该数字和其以后的数字,T(n) = O(n^2) (1)总体的意思就是将数组分成两段,首先求段内的逆序对数量,比如下面两段代码就是求左右两端数组段内的逆序对数量 count += Merge(data, temp, first, mid);//找左半段的逆序对数目 count += Merge(data, temp, mid + 1, e

HDU 5273 Dylans loves sequence (逆序对,暴力)

题意:给定一个序列,对于q个询问:(L,R)之间有几个逆序对?序列元素个数上限1000,q上限10万.仅1测试例子. 思路: 先分析: [L,R]的逆序对数量可以这么算,假设L<=K<R,将区间拆成两部分,那么[L,k]中的逆序对要算上, (k,R]中的逆序对也要算上,还有一些逆序对假设为(l,r),l在左部分,r在右部分.则应该是3部分来构成,设3部分为A,B,C,那么ans=A+B+C . 而如果将k移到最右边,比如k=R-1,那么区间拆成[L,k]和(K,R],而(K,R]其实就只有R一

逆序对问题---求逆序数

逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反, 即前面的数大于后面的数,那么它们就称为一个逆序. 一个排列中逆序的总数就称为这个排列的逆序数.逆序数为偶数的排列称为偶排列:逆序数为奇数的排列称为奇排列. { 设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同. 如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这一个有序对称为 A 的一个逆序对,也称作逆序.逆序对的数量称作逆

BZOJ 3295:[Cqoi2011]动态逆序对(三维偏序 CDQ分治+树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=3295 题意:简单明了. 思路:终于好像有点明白CDQ分治处理三维偏序了.把删除操作看作是插入操作,那么可以按照插入的时间顺序看作是一维x,插入的数在原本序列的下标是一维y,插入的数本身是一维z.那么问题可以转化成每插入一个数(xx,yy,zz),求有多少个数(x,y,z)使得 x < xx,y < yy,z > zz .一开始先对 x 进行排序,然后进行CDQ分治.这样可以干掉一维,保证随