题目链接:http://poj.org/problem?id=2299
题目大意:通过交换相邻两个的序列元素,使得序列为升序,问你最小需要多少次。
解题思路:实质就要你求该序列的逆序数。求逆序数有两种求法。一种是归并排序,还有一种就是树状数组。
1.归并排序:
#include <iostream> #include <cstdio> #include <algorithm> #define INF 0xfffffff using namespace std; typedef __int64 ll; int a[500005]; int L[250005],R[250005]; ll cnt; void Merge(int a[],int l,int mid,int r) { int n1 = mid-l+1; int n2 = r-mid; int i,j,k; for(i = 1; i <= n1; i++) L[i] = a[l+i-1]; for(i = 1; i <= n2 ;i++) R[i] = a[mid+i]; L[n1+1] = INF; R[n2+1] = INF; i = 1; j = 1; for(k = l; k <= r; k++) { if(L[i] <= R[j]) { a[k] = L[i]; i++; } else { a[k] = R[j]; j++; cnt += (ll)(n1-i+1); } } } void Merge_sort(int a[],int l,int r) { if(l < r) { int mid = (l+r)>>1; Merge_sort(a,l,mid); Merge_sort(a,mid+1,r); Merge(a,l,mid,r); } } int main() { int n; while(scanf("%d",&n),n) { int i; cnt = 0; for(i = 1; i <= n; i++) scanf("%d",&a[i]); Merge_sort(a,1,n); printf("%I64d\n",cnt); } return 0; }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef __int64 ll; int n; int d[500005];//离散化后的数组 int c[500005]; struct node { int id; int num; }v[500005]; bool cmp(node a,node b) { if(a.num == b.num) return a.id < b.id; return a.num < b.num; } int lowbit(int x) { return x&(-x); } void update(int x) { while(x <= n) { c[x] += 1; x += lowbit(x); } } int getsum(int x) { int sum = 0; while(x) { sum += c[x]; x -= lowbit(x); } return sum; } int main() { while(scanf("%d",&n),n) { int i; ll ans = 0; for(i = 1; i <= n; i++) { scanf("%d",&v[i].num); v[i].id = i; } sort(v+1,v+n+1,cmp); for(i = 1; i <= n; i++) d[v[i].id] = i; memset(c,0,sizeof(c)); for(i = 1; i <= n; i++) { update(d[i]); ans += (ll)(i-getsum(d[i])); } printf("%I64d\n",ans); } return 0; }