题目大意
给一组数,问最少经过多少次相邻交换可以将他们变成升序排列
n<500000;a[i]<999999999;
分析
【错误思路】一开始没仔细想太多拿着一个快排算法就开始写了,原本想的是,快排中第一个元素的右边比它小的一定会交换到它的右边,将快拍算法递归中的每一层的第一个元素右边比它小的数的个数加起来的和就是最终答案。样例是过了,其实这样是错误的。
在WA了之后改用树状数组写了一发结果RE,回去读题才注意到原来数的范围太大,我想到的是用map来实现离散化将这些数映射到1~500000的范围。TLE了几次,看别人的博客才发现不用map直接一个数组和结构体就能搞定,可能是这里用map效率有点低才超时吧。
代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
int n;
int a[500005];
long long int ans=0;
long long int C[500005];
int max_num;
map<int,int> Hash;
struct Node
{
int val;
int pos;
}node[500005];
int reflect[500005];
long long int Sum(int x)
{
long long int ret=0;
while(x>0)
{
ret+=C[x];
x-=(x&(-x));
}
return ret;
}
void Add(int x,int m)
{
while(x<=n)
{
C[x]+=m;
x+=x&(-x);
}
}
void Work()
{
for(int i=1;i<=n;i++)C[i]=0;
for(int i=n;i>=1;i--)
{
int t=reflect[i];
ans+=Sum(t);
Add(t,1);
}
}
bool cmp(const Node& a, const Node& b)
{
return a.val < b.val;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==0)break;
ans=0;
max_num=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].val);
node[i].pos=i;
}
sort(node+1,node+n+1,cmp);
for(int i=1;i<=n;i++)reflect[node[i].pos]=i;
Work();
cout<<ans<<endl;
}
}
//3 999999999 2 1
本文介绍了解决POJ2299问题的方法,该问题是求解最少相邻交换次数使序列升序。文章首先介绍了错误的快速排序思路,然后详细解释了使用树状数组的正确解法,并通过离散化处理大数据范围。
236

被折叠的 条评论
为什么被折叠?



