题目链接: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;
}
2.树状数组
#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;
}