什么叫逆序数
对于某一个数来说,它的逆序数等于在它之前有多少个比它大的数
对于某一个序列来说,逆序数等于所有数的逆序数之和
例如
序列 5 1 5 2
逆序数 0 1 0 2
序列的逆序数 1+2=3
来看逆序数的求法
首先将定义一个结构体,存数列的值和下标,然后按数值从大到小(数值相同按下标从大到小)sort一下
然后建立树状数组,从最大的元素开始,将其标记,即 add(p【i】.id,1)
利用其query(i)查询当前1----i的和,即从1-----i一共有多少个标记的数
对于第i大的数,由于之前所有比它大的数已经标记,所以query(i)就是当前数的逆序数
对于序列的逆序数,只需要加起来就可以了
代码
#include
using namespace std;
#define ll long long
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define minn(x,y,z) min(min(x,y),z)
struct node
{
int x,i;
bool operator < (const node &a) const
{
if(x!=a.x)
return x0;i--)
{
int ccc =p[i].i;
cnt = cnt + query(ccc);
add(ccc);
}
printf("%lld\n",cnt);
}
return 0;
}
也是树状数组,不过要离散化处理
所谓的离散化就是将数组排个序,例如从小到大排序,
那么将第一小记做1,第二小记做2,那么就算是离散化了
(离散,字面意思,分离,散开,分成一个个的小块,当然每个块不能相同)
这个处理的话就是这样
序列 5 1 5 2
离散化数组 3 1 3 2
这样从最小的数开始建立树状数组(标记)
那么i-query(b【i】)就是当前数的逆序数(i为当前第i个的数,b【i】是当前数是第几小,
query询问的是1------i有多少个标记的数(小于等于当前数的数),i-query(b【i】)自然是大于当前数 的数 的个数)
补充一个
离散化三部曲:
1. 数组 ha[] 存储所有存在过的数据,sort排序
2. 对ha数组进行去重,重复的数据只保留一个。unique去重(unique函数前提有序)
3. 查询某个数字离散化之后对应的数字,lower_bound查排名
代码
#include
#include
#include
#include
#define ll long long
using namespace std;
int n,tree[100010];
void add(int k,int num)
{
while(k<=n)
{
tree[k]+=num;
k+=k&-k;
}
}
int query(int k)
{
int sum=0;
while(k)
{
sum+=tree[k];
k-=k&-k;
}
return sum;
}
struct node
{
int x,i;
bool operator < (const node &a) const
{
return x
归并求解
相当漂亮的写法,让我写肯定写不了这么好,但是有个问题是b数组的申请,这里频繁申请爆掉了
我给改成了全局变量
#include
using namespace std;
long long int cnt;
int a[104000];
int *b;
void Merge(int a[], int low, int mid, int high);
void Merge_sort(int a[], int low, int high);///归并排序
int main(){
int n, i;
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
b = new int[n];
cnt = 0;
Merge_sort(a, 0, n-1);
delete[] b;
printf("%lld\n", cnt);
return 0;
}
void Merge_sort(int a[], int low, int high){
int mid;
if(low < high){
mid = (low + high)/2;
Merge_sort(a, low, mid);
Merge_sort(a, mid+1, high);
Merge(a, low, mid, high);
}
}
void Merge(int a[], int low, int mid, int high){///可类比两组有序链表的归并,思想基本一样
int i = low;
int j = mid + 1;
int k = 0;
//int *b = new int[high-low+1];///动态申请内存
while(i <= mid && j <= high){
if(a[i] <= a[j])
b[k++] = a[i++];
else {
b[k++] = a[j++];
cnt += (mid - i + 1);///归并两组有序数据,当a[i] > a[j], 则在区间[i, mid]的数据全部大于a[j],此时对于a[j]的逆序数为(mid - i + 1)
}
}
while(i <= mid){
b[k++] = a[i++];
}
while(j <= high){
b[k++] = a[j++];
}
for(k = 0, i = low; i <= high; i++, k++){
a[i] = b[k];
}
}
方法四
直接数 的就不写了