P1908 逆序对
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
输入输出格式
输入格式:
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。
输出格式:
给定序列中逆序对的数目。
输入输出样例
说明
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define date 100005 using namespace std; int n; long long ans; int num[date]; int sum[date]; void merge_sort(int l,int r) { if(l<r) { int mid=(l+r)/2; int x=l; int y=mid+1; int i=l; merge_sort(l,mid); merge_sort(mid+1,r); while(x<=mid||y<=r) { if(y>r||(x<=mid&&num[x]<=num[y])) { sum[i++]=num[x++]; } else { sum[i++]=num[y++]; ans+=mid-x+1; } } for(i=l;i<=r;i++) { num[i]=sum[i]; } } } void init() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } merge_sort(1,n); cout<<ans; } int main() { init(); return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,ans,id[40005],c[40005]; struct NUM { int num,id; }num[40005]; bool cmp(NUM a,NUM b) { return a.num>b.num; } int lowbit(int x) { return x&(-x); } void add(int x) { while(x<=n) { c[x]++; x+=lowbit(x); } } int sum(int x) { int sum=0; while(x) { sum+=c[x]; x-=lowbit(x); } return sum; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&num[i].num); num[i].id=i; //离散化处理 } sort(num+1,num+n+1,cmp); for(int i=1;i<=n;i++) { id[num[i].id]=i; } for(int i=1;i<=n;i++) { ans+=sum(id[i]); add(id[i]); } printf("%d",ans); return 0; }
/* 貌似是题解里唯一的一篇线段树题解。 本来是要做动态逆序对的,但是我不会cdq分治,树状数组和分块不熟悉,所以想写线段树套线段树。 然后就先来用线段树做一下不动态的。 5倍空间消耗,比较慢,跑了近300ms 要离散化 指针+动态开点 */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=4e4+5; int n,a,ans; struct Num { int num,id; }num[N],aha[N]; struct Node { Node *lson,*rson; int sum; }node[N<<2]; typedef Node* Tree; Tree now_node,root,null; bool cmp1(Num a,Num b) { return a.num<b.num; } bool cmp2(Num a,Num b) { return a.id<b.id; } void init() { node->lson=node->rson=node; now_node=null=root=node; } int read() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } Tree newNode() { ++now_node; now_node->lson=now_node->rson=null; return now_node; } int query(Tree &root,int l,int r,int L,int R) { if(root==null) return 0; if(L<=l&&r<=R) return root->sum; int mid=l+r>>1; int ret=0; if(L<=mid) ret+=query(root->lson,l,mid,L,R); if(mid<R) ret+=query(root->rson,mid+1,r,L,R); return ret; } void modify(Tree &root,int l,int r,int pos) { if(root==null) root=newNode(); if(l==r) { root->sum=1; return; } int mid=l+r>>1; if(pos<=mid) modify(root->lson,l,mid,pos); else modify(root->rson,mid+1,r,pos); root->sum=root->lson->sum+root->rson->sum; } int main() { //freopen("testdata.in","r",stdin); init(); n=read(); for(int i=1;i<=n;++i) { num[i].num=read(); num[i].id=i; aha[i].id=i; } sort(num+1,num+n+1,cmp1); for(int i=1;i<=n;++i) //离散化,按大小编新的编号 aha[num[i].id].num=i; //sort(aha+1,aha+n+1,cmp2); //按输入顺序排序,还原原序列 for(int i=1;i<=n;++i) { ans+=query(root,1,n,aha[i].num,n); //查找在它之前的比它大的数 modify(root,1,n,aha[i].num); //标记一下这个数已经出现 } printf("%d",ans); return 0; }