题目意思是求一个序列的逆序数,朴素的做法时间复杂度是O(n^2),其中 n < 500,000 ,结果不用说肯定是超时的;于是思路转向了O(nlogn)的算法,换言之离不开二分、树型结构等方法
这里用到的是杨挺的PDF《树状数组和线段树》里提到的方法:巧妙地将问题转化成类似求RMQ的问题,然后通过树状树组解决
1,将序列离散化,即序列内第k小的元素变成k,注意到题目已说明序列内无相同元素;离散化可通过排序和二分查找解决
2,将b[]初始化为0,遍历离散化后的序列a[1~n],每当向树状数组c[]插入a[i]前,根据c[]用O(logn)的时间求b[1]~b[a[i]]的和,即求得比a[i]先插入且比a[i]小的元素个数(放到序列上理解,就是排在a[i]前面且比a[i]小的元素个数),换算后可得比a[i]先插入且比a[i]大的元素个数,在遍历过程中将其累加到ans,即为答案
3,更新ans后置b[a[i]]为1,同时更新c[]的值(对c[]插入a[i])
排序和统计的复杂度都为O(nlogn),所以算法总复杂度是O(nlogn)
#include
<
iostream
>
#include < algorithm >
using namespace std;
#define MAXN 500005
#define clr(x) memset(x,0,sizeof(x))
int a[MAXN],b[MAXN],c[MAXN],n;
__int64 ans;
int find( int x){
int l = 1 ,r = n,m;
while (r >= l){
m = (l + r) / 2 ;
if (x < b[m])
r = m - 1 ;
else if (x > b[m])
l = m + 1 ;
else
return m;
}
return - 1 ;
}
void discretization(){
int i,t;
for (i = 1 ;i <= n;i ++ ){
t = find(a[i]);
a[i] = t;
}
}
inline int lowbit( int x){
return x & ( - x);
}
int sum( int k){ // 求sum(b[1]~b[k])
int i,res = 0 ;
for (i = k;i > 0 ;i -= lowbit(i))
res += c[i];
return res;
}
void improve( int k){ // 插入a[i]后b[a[i]]的值有修改
int i;
// 若对b[k]有修改,设影响到了c[p1]、c[p2]、
,则p1=k,pi+1=pi + lowbit(pi)
for (i = k;i <= n;i += lowbit(i))
c[i] ++ ;
}
void build(){ // 建立树状数组c[]
clr(b);
clr(c);
int i,k;
for (i = 1 ;i <= n;i ++ ){
k = a[i];
ans += i - sum(k) - 1 ;
b[k] = 1 ;
improve(k);
}
}
int main(){
int i;
while (scanf( " %d " , & n) && n){
for (i = 1 ;i <= n;i ++ ){
scanf( " %d " ,a + i);
b[i] = a[i];
}
sort(b + 1 ,b + n + 1 );
discretization(); // 离散化
ans = 0 ;
build();
printf( " %I64d\n " ,ans);
}
return 0 ;
}
#include < algorithm >
using namespace std;
#define MAXN 500005
#define clr(x) memset(x,0,sizeof(x))
int a[MAXN],b[MAXN],c[MAXN],n;
__int64 ans;
int find( int x){
int l = 1 ,r = n,m;
while (r >= l){
m = (l + r) / 2 ;
if (x < b[m])
r = m - 1 ;
else if (x > b[m])
l = m + 1 ;
else
return m;
}
return - 1 ;
}
void discretization(){
int i,t;
for (i = 1 ;i <= n;i ++ ){
t = find(a[i]);
a[i] = t;
}
}
inline int lowbit( int x){
return x & ( - x);
}
int sum( int k){ // 求sum(b[1]~b[k])
int i,res = 0 ;
for (i = k;i > 0 ;i -= lowbit(i))
res += c[i];
return res;
}
void improve( int k){ // 插入a[i]后b[a[i]]的值有修改
int i;
// 若对b[k]有修改,设影响到了c[p1]、c[p2]、
![](https://www.cnblogs.com/Images/dot.gif)
for (i = k;i <= n;i += lowbit(i))
c[i] ++ ;
}
void build(){ // 建立树状数组c[]
clr(b);
clr(c);
int i,k;
for (i = 1 ;i <= n;i ++ ){
k = a[i];
ans += i - sum(k) - 1 ;
b[k] = 1 ;
improve(k);
}
}
int main(){
int i;
while (scanf( " %d " , & n) && n){
for (i = 1 ;i <= n;i ++ ){
scanf( " %d " ,a + i);
b[i] = a[i];
}
sort(b + 1 ,b + n + 1 );
discretization(); // 离散化
ans = 0 ;
build();
printf( " %I64d\n " ,ans);
}
return 0 ;
}
另附合并排序求逆序数代码:
#include
<
iostream
>
#include < algorithm >
using namespace std;
#define MAXN 500001
int a[MAXN],t[MAXN],n;
__int64 ans;
void Merge( int l, int m, int r){
int i = 0 ,j = l,k = m + 1 ;
while (j <= m && k <= r){
if (a[j] > a[k]){
t[i ++ ] = a[k ++ ];
ans += m - j + 1 ;
}
else
t[i ++ ] = a[j ++ ];
}
while (j <= m)
t[i ++ ] = a[j ++ ];
while (k <= r)
t[i ++ ] = a[k ++ ];
for (j = 0 ;j < i;j ++ ){
a[l + j] = t[j];
}
}
void Mergesort( int l, int r){
if (l < r){
int m = (l + r) / 2 ;
Mergesort(l,m);
Mergesort(m + 1 ,r);
Merge(l,m,r);
}
}
int main(){
int i;
while (scanf( " %d " , & n) && n){
ans = 0 ;
for (i = 0 ;i < n;i ++ )
scanf( " %d " ,a + i);
Mergesort( 0 ,n - 1 );
printf( " %I64d\n " ,ans);
}
return 0 ;
}
#include < algorithm >
using namespace std;
#define MAXN 500001
int a[MAXN],t[MAXN],n;
__int64 ans;
void Merge( int l, int m, int r){
int i = 0 ,j = l,k = m + 1 ;
while (j <= m && k <= r){
if (a[j] > a[k]){
t[i ++ ] = a[k ++ ];
ans += m - j + 1 ;
}
else
t[i ++ ] = a[j ++ ];
}
while (j <= m)
t[i ++ ] = a[j ++ ];
while (k <= r)
t[i ++ ] = a[k ++ ];
for (j = 0 ;j < i;j ++ ){
a[l + j] = t[j];
}
}
void Mergesort( int l, int r){
if (l < r){
int m = (l + r) / 2 ;
Mergesort(l,m);
Mergesort(m + 1 ,r);
Merge(l,m,r);
}
}
int main(){
int i;
while (scanf( " %d " , & n) && n){
ans = 0 ;
for (i = 0 ;i < n;i ++ )
scanf( " %d " ,a + i);
Mergesort( 0 ,n - 1 );
printf( " %I64d\n " ,ans);
}
return 0 ;
}