Description
![](https://i-blog.csdnimg.cn/blog_migrate/b3530eaa8fa98ef394d3639722240a8c.jpeg)
Ultra-QuickSort produces the output
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input
Output
Sample Input
5 9 1 0 5 4 3 1 2 3 0
Sample Output
6 0
题意:给你一组数,规定只能交换相邻的数,问最少交换多少次才能使这组数按升序排列。
心得:第一眼看题的时候,一想相邻元素之间交换,果断脑残地想到了冒泡啊,多聪明。。。一交TLE,这不是必须超嘛,要是不超,就是出题的二货了。后来,才知道这题也是求逆序数的,因为有多少逆序数,就必须交换多少次才能变成有序的。
分析:又是求逆序数问题。果断再次树状数组搞一下,如果数据不是很大, 可以一个个插入到树状数组中, 每插入一个数, 统计比他小的数的个数,对应的逆序为 i- getsum( data[i] ),其中 i 为当前已经插入的数的个数,sum(data[i])为比 data[i] 小的数的个数i- sum(data[i]) 即比 data[i] 大的个数, 即逆序的个数。
离散化:
一关键字的离散化方法:
所谓离散化也就是建立一个一对一的映射。 因为求逆序时只须要求数据的相应大小关系不变。
如: 10 30 20 40 50 与 1 3 2 4 5 的逆序数是相同的
定义一个结构体 struct Node{ int data; // 对应数据
int pos; // 数据的输入顺序 };
先对 data 升序排序, 排序后,pos 值对应于排序前 data 在数组中的位置。再定义一个数组 p[N], 这个数组为原数组的映射。以下语句将按大小关系
把原数组与 1到 N 建立一一映射。
int id= 1; p[ d[1].pos ]= 1;
for( int i= 2; i<= n; ++i )
if( d[i].data== d[i-1].data ) p[ d[i].pos ]= id;
else p[ d[i].pos ]= ++id;
二关健字的离散方法:
先对第一个关键字进行离散化,然后对第二关键字排序。
本题是一个关键字的离散化。
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#define INF 0x7fffffff
#define LL long long
using namespace std;
const int maxn = 500000 + 10;
const int maxx = 999999999;
LL c[maxn];
struct node
{
int pos,val;
};
node a[maxn];
int reflect[maxn];
int n;
bool cmp(const node a,const node b)
{
return a.val<b.val;
}
int lowbit(int x)
{
return x & (-x);
}
void add(int x,int d)
{
while(x <= n)
{
c[x] += d;
x += lowbit(x);
}
}
int sum(int x)
{
int ret = 0;
while(x > 0)
{
ret += c[x];
x -= lowbit(x);
}
return ret;
}
int main()
{
while(scanf("%d",&n)!=EOF && n)
{
LL cnt = 0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i].val);
a[i].pos = i;
}
sort(a+1,a+1+n,cmp);
for(int i=1; i<=n; i++) c[i]=0;
for(int i=1; i<=n; i++) reflect[a[i].pos] = i; //离散化
for(int i=1; i<=n; i++)
{
add(reflect[i],1);
cnt += i - sum(reflect[i]); //求逆序数
}
printf("%lld\n",cnt);
}
return 0;
}