之前不知道逆序数是什么,今天才了解了一下,主要朴素的方法是n^2的,所以可以用归并排序,线段树还有树状数组三种方法来做。
先学了归并排序的做法,发现还是挺简单的。~~
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 5e5+5;
int num[maxn],p[maxn];
long long cnt;
void hhsort(int *num,int left,int mid,int right,int *p) {
int i = left,j = mid+1,k = 0;
while(i <= mid && j <= right) {
if(num[i] < num[j])
p[k++] = num[i++];
else {
p[k++] = num[j++];
cnt += mid - i + 1; //cnt用long long来存,然后根据归并排序的原理第二段(后面那段)先加的就是存在逆序数,且逆序数为mid-i+1
}
}
while(i <= mid)
p[k++] = num[i++];
while(j <= right)
p[k++] = num[j++];
for(i = 0;i < k;i++)
num[left + i] = p[i];
}
void qqsort(int *num,int left,int right,int *p) { //调用递归
if(left < right) {
int mid = (left + right) >> 1;
qqsort(num,left,mid,p);
qqsort(num,mid+1,right,p);
hhsort(num,left,mid,right,p);
}
}
int main() {
int t;
while(scanf("%d",&t) && t) {
for(int i = 0;i < t;i++)
scanf("%d",&num[i]);
cnt = 0;
qqsort(num,0,t-1,p);
printf("%I64d\n",cnt); //g++里面输出输入long long用I64d比较好
}
return 0;
}
后面再补上树状数组的方法--------------
还是忘了开long long WA了一发,Orz。
树状数组的做法主要是要了解一个方法,定义一个为0的数组P【n】,把给的数列按从大到小的顺序插,插入一个就把当前位置P【i】+1,再看P【i】之前有木有插过数字,即getsum(i-1).,最后把这些都加起来,就是逆序数的个数,最后的总数加起来会爆int,所以别忘了cnt定义为longlong~
树状数组写起来就是很短,不错~
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
struct nu {
int x,t;
} num[500005];
int n,p[500005];
long long cnt;
bool cmp(nu a,nu b) {
return a.x > b.x;
}
int lowbit(int t) {
return t & (-t);
}
int getsum(int t) {
int tt = 0;
while(t) {
tt += p[t];
t -= lowbit(t);
}
return tt;
}
void add(int t,int x) {
int ss = t;
while(t <= n) {
p[t] += x;
t += lowbit(t);
}
cnt += getsum(ss-1);
}
int main() {
while(scanf("%d",&n) && n) {
memset(p,0,sizeof(p));
for(int i = 1;i <= n;i++) {
scanf("%d",&num[i].x);
num[i].t = i;
}
sort(num+1,num+1+n,cmp);
cnt = 0;
for(int i = 1;i <= n;i++) {
add(num[i].t,1);
}
printf("%I64d\n",cnt);
}
return 0;
}