题目描述 Description
给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目
数据范围:N<=105。Ai<=105。时间限制为1s。
输入描述 Input Description
第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数。
输出描述 Output Description
所有逆序对总数.
样例输入 Sample Input
4
3
2
3
2
样例输出 Sample Output
3
数据范围及提示 Data Size & Hint
分类标签 Tags 点此展开
注意要点:
1、最后输出的数据要用 long long
2、代码重点处解释:
若a[p]>a[j],而且我们用分治早已排成升序形式,所以得出a[p]到mid之间所有数都会大于a[j],所以k=k+mid-p+1, +1补充我们减去的a[p]。
归并排序求逆序对
#include<cstdio> #include<iostream> #define N 100100 using namespace std; int a[N],b[N],n; long long k; void binary_chop(int l,int r){ if(l==r) return ; int mid=(l+r>>1); binary_chop(l,mid);binary_chop(mid+1,r); int p=l,q=l,j=mid+1; while(p<=mid&&j<=r){ if(a[p]>a[j]){ k+=mid-p+1;//重点 b[q++]=a[j++]; } else{ b[q++]=a[p++]; } } while(p<=mid) b[q++]=a[p++]; while(j<=r) b[q++]=a[j++]; for(int i=l;i<=r;i++) a[i]=b[i]; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",a+i); } binary_chop(1,n); cout<<k<<endl; return 0; }
树状数组求逆序对
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=1e5+10; int n,cnt,a[N],b[N],c[N]; ll ans; inline int lowbit(int x){ return x&-x; } void updata(int p,int v){ for(int i=p;i<=n;i+=lowbit(i)) c[i]+=v; } int query(int p){ int res=0; for(int i=p;i;i-=lowbit(i)) res+=c[i]; return res; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); memcpy(b,a,sizeof a); sort(b+1,b+n+1); cnt=unique(b+1,b+n+1)-(b+1); for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b; for(int i=1;i<=n;i++){ ans+=(ll)(query(cnt)-query(a[i])); updata(a[i],1); } printf("%lld",ans); return 0; }