题目链接:二分·归并排序之逆序对
题目大意:N个整数,第i个数表示等级第i低的船的火力值a[i],求A船比B船等级高,但是A船火力低于B船,相当于就是求逆序数吧
解题思路:
- 把序列分成元素个数尽量相等的两半
- 把两半元素分别排序
- 把两个有序表合并成一个
二分归并排序做法:
/************************************************************** Problem:hiho 1141 User: youmi Language: C++ Result: Accepted Time:148ms Memory:7M ****************************************************************/ //#pragma comment(linker, "/STACK:1024000000,1024000000") //#include<bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <stack> #include <set> #include <sstream> #include <cmath> #include <queue> #include <string> #include <vector> #define zeros(a) memset(a,0,sizeof(a)) #define ones(a) memset(a,-1,sizeof(a)) #define sc(a) scanf("%d",&a) #define sc2(a,b) scanf("%d%d",&a,&b) #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scs(a) scanf("%s",a) #define sclld(a) scanf("%I64d",&a) #define pt(a) printf("%d\n",a) #define ptlld(a) printf("%I64d\n",a) #define rep0(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define rep_1(i,n) for(int i=n;i>=1;i--) #define rep_0(i,n) for(int i=n-1;i>=0;i--) #define Max(a,b) (a)>(b)?(a):(b) #define Min(a,b) (a)<(b)?(a):(b) #define lson (step<<1) #define rson (lson+1) #define esp 1e-6 #define oo 0x3fffffff #define TEST cout<<"*************************"<<endl using namespace std; typedef long long ll; int n; const int maxn=100000+10; ll d[maxn]; ll p[maxn]; ll ans; void test(int l,int r)//输出排序过程,检验正确与否 { printf("l->%d r->%d\n",l,r); for(int i=l;i<=r;i++) printf("%d ",d[i]); cout<<endl; } void merge_sort(int l,int r)//因为每一次排序只与l--r这段有关,所以可以把这段的排序结果放在p数组里,排完后再复制回原数组 { if(l<r) { int mid=(l+r)>>1; merge_sort(l,mid); merge_sort(mid+1,r); int x=l,y=mid+1; int cnt=0; while(x<=mid||y<=r) { if(y>r||(x<=mid&&d[x]<=d[y])) p[cnt++]=d[x++]; else { p[cnt++]=d[y++]; ans+=(x-l);//每次排序左半边的下标比右半边小,所以只需要在每次放右半边的数时看看左半边已经排好了多少,相应的就知道有多少等级高但值比下标大值小的数有多少 } } int temp=l; rep0(i,cnt) d[temp++]=p[i]; } } int main() { //freopen("in.txt","r",stdin); while(~sc(n)) { rep1(i,n) scanf("%lld",&d[i]); ans=0; merge_sort(1,n); printf("%lld\n",1ll*n*(n-1)/2-ans); } return 0; }
树状数组也是求逆序数的好方法,每放一个数,就比他小的数有多少个,也就是等级比他大但数值比他小的数量
/************************************************************** Problem:hiho 1141 User: youmi Language: C++ Result: Accepted Time:151ms Memory:6M ****************************************************************/ //#pragma comment(linker, "/STACK:1024000000,1024000000") //#include<bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <stack> #include <set> #include <sstream> #include <cmath> #include <queue> #include <string> #include <vector> #define zeros(a) memset(a,0,sizeof(a)) #define ones(a) memset(a,-1,sizeof(a)) #define sc(a) scanf("%d",&a) #define sc2(a,b) scanf("%d%d",&a,&b) #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scs(a) scanf("%s",a) #define sclld(a) scanf("%I64d",&a) #define pt(a) printf("%d\n",a) #define ptlld(a) printf("%I64d\n",a) #define rep0(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define rep_1(i,n) for(int i=n;i>=1;i--) #define rep_0(i,n) for(int i=n-1;i>=0;i--) #define Max(a,b) (a)>(b)?(a):(b) #define Min(a,b) (a)<(b)?(a):(b) #define lson (step<<1) #define rson (lson+1) #define esp 1e-6 #define oo 0x3fffffff #define TEST cout<<"*************************"<<endl using namespace std; typedef long long ll; int n; const int maxn=100000+10; int b[maxn],c[maxn]; struct node { int val,id; bool operator<(const node& a)const { return val<a.val; } }a[maxn]; int lowbit(int x) { return x&(-x); } void update(int x) { while(x<=n) { c[x]+=1; x+=lowbit(x); } } int query(int x) { int res=0; while(x>=1) { res+=c[x]; x-=lowbit(x); } return res; } int main() { //freopen("in.txt","r",stdin); while(~sc(n)) { rep1(i,n) { sc(a[i].val); a[i].id=i; } sort(a+1,a+n+1);//下面为离散化过程,因为单个值太大,如果开相应大小的数组就爆栈了 b[a[1].id]=1; for(int i=2;i<=n;i++) { if(a[i].val!=a[i-1].val) b[a[i].id]=i; else b[a[i].id]=b[a[i-1].id]; }//以上为离散化过程 /**<rep1(i,n) printf("%d ",b[i]); cout<<endl; */ zeros(c); ll ans=0; rep1(i,n) { ans+=query(b[i]); update(b[i]); } ll temp=1ll*n*(n-1)/2-ans; printf("%lld\n",temp); } return 0; }
不为失败找借口,只为成功找方法