题目链接:
http://poj.org/problem?id=2299
分析与总结:
一看到这题的第一反应就觉得是求逆序数 = =|
先用归并排序求逆序数AC之,这应该是速度最快的一种求逆序数方法,391MS
然后用树状数组做,因为每个元素范围0 ≤ a[i] ≤ 999,999,999, 太大了,所以我用map离散化了,结果超时了...
后来发现,其实不需要用map来映射,之所以用map是应为元素的值太大了,但是其实不需要映射元素的值,只需要映射元素的下标位置即可!而最多只有50W个数,可以直接用数组保存,这样就可以O(1)的时间得到映射的值了。
最后又再用线段树搞了下,用了922MS...
代码:
1. 树状数组+离散化
#include<iostream> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<algorithm> using namespace std; const int MAXN = 500005; typedef long long int64; int n,arr[MAXN],rank[MAXN]; int64 c[MAXN], cnt,id; struct node{ int val, id; friend bool operator<(const node&a,const node&b){ return a.val < b.val; } }tmp[MAXN]; inline int lowbit(int x) {return x&(-x);} int64 sum(int x){ int64 ret=0; while(x>0){ ret += c[x]; x -= lowbit(x); } return ret; } void add(int x){ while(x <= id){ ++c[x]; x += lowbit(x); } } int main(){ while(~scanf("%d",&n) && n){ memset(c, 0, sizeof(c)); for(int i=0; i<n; ++i){ scanf("%d",&arr[i]); tmp[i].val = arr[i]; tmp[i].id = i; } sort(tmp, tmp+n); id = 1; for(int i=0; i<n; ++i){ if(!i || tmp[i].val!=tmp[i-1].val) rank[tmp[i].id] = id++; else rank[tmp[i].id] = rank[tmp[i-1].id]; } int64 ans=0; for(int i=0; i<n; ++i){ int x = rank[i]; ans += sum(id)-sum(x); add(x); } printf("%lld\n",ans); cnt = 0; } return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define mid ((left+right)>>1) #define lson rt<<1, left, m #define rson rt<<1|1,m+1,right using namespace std; const int MAXN = 500010; typedef long long int64; int n,arr[MAXN],rank[MAXN]; int64 c[MAXN<<2]; struct node{ int val, id; friend bool operator<(const node&a,const node&b){ return a.val < b.val; } }tmp[MAXN]; void update(int rt,int left,int right,int data){ ++c[rt]; if(left==right) return; int m = mid; if(data <= m) update(lson,data); else update(rson,data); } int64 query(int rt,int left,int right,int l,int r){ if(left==l && right==r) return c[rt]; int m = mid; if(r <= m) return query(lson,l,r); else if(l > m) return query(rson,l,r); else return query(lson,l,mid)+query(rson,mid+1,r); } int main(){ while(~scanf("%d",&n) && n){ memset(c, 0, sizeof(c)); memset(rank, 0, sizeof(rank)); for(int i=0; i<n; ++i){ scanf("%d",&arr[i]); tmp[i].val = arr[i]; tmp[i].id = i; } sort(tmp, tmp+n); for(int i=0; i<n; ++i){ rank[tmp[i].id] = i+1; } int64 ans=0; for(int i=0; i<n; ++i){ int x = rank[i]; ans += query(1,1,n+1,x+1,n+1); update(1,1,n+1,x); } printf("%lld\n",ans); } return 0; }
3. 归并排序求逆序数
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 500005; typedef long long int64; int n,arr[MAXN], tmp[MAXN]; int64 cnt; void merge_sort(int *A,int x,int y,int *T){ if(y-x > 1){ int m=(x+y)>>1; // 划分 int p=x, q=m, i=x; merge_sort(A,x,m,T); merge_sort(A,m,y,T); while(p<m || q<y){ if(q>=y || (p<m && A[p] <= A[q])) T[i++] = A[p++]; else { T[i++] = A[q++]; cnt += m-p; } } for(i=x; i<y; ++i) A[i]=T[i]; } } int main(){ while(~scanf("%d",&n) && n){ for(int i=0; i<n; ++i){ scanf("%d",&arr[i]); tmp[i] = arr[i]; } cnt = 0; merge_sort(arr,0,n,tmp); printf("%lld\n",cnt); } return 0; }
—— 生命的意义,在于赋予它意义士。
原创http://blog.csdn.net/shuangde800,By D_Double (转载请标明)