Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 60497 | Accepted: 22431 |
Description
Ultra-QuickSort produces the output
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input
Output
Sample Input
5 9 1 0 5 4 3 1 2 3 0
Sample Output
6 0
归并排序,或用树状数组记录,先写树状数组
1:树状数组,对于题目来说 999,999,999的数据范围,开数组肯定要爆内存,由于n只有500000,可以对数据离散化一下,把每个数据改成1~n之间的数,拿第一组数据来说,9最大,9的角标为1,所以让a[1]=5;
先上个改上界,求下界的码,不太好看懂,感觉有点绕;
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 500010
typedef long long LL;
struct node
{
int x,pos;
}q[maxn];
int a[maxn],num[maxn];
int n;
int lowbit(int x)
{
return x&-x;
}
bool cmp(node s,node b)
{
return s.x<b.x;
}
void add(int i,int x)
{
while(i<=n)
{
a[i]+=x;
i+=lowbit(i);
}
}
int getsum(int i)
{
int sum=0;
while(i>0)
{
sum+=a[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
while(~scanf("%d",&n),n)
{
memset(a,0,sizeof(a));//注意清零
for(int i=1;i<=n;++i)
{
scanf("%d",&q[i].x);
q[i].pos=i;//记录原始的位置
}
sort(q+1,q+n+1,cmp);
for(int i=1;i<=n;++i)
num[q[i].pos]=i;//离散化
LL ans=0;
for(int i=1;i<=n;++i)
{
ans+=(i-1)-getsum(num[i]);//前面有i-1个数,getsum(num[i])为小于num[i]的数
add(num[i],1);//加入数组中
}
printf("%lld\n",ans);
}
return 0;
}
下面是自己改的,改下界求上界的码,个人感觉很简洁
既然每次更新的是1~a[i]之间<=a[i]的个数,那么我读取的时候直接读a[i]~n不就是a[i]~n之间>=a[i]的值吗?
关于相等的情况:会有这样一个问题,读取的时候为什么不是a[i]~n之间>=a[i],那么如果出现两个值相等的情况呢?,我考虑了很久关于这个问题,其实没必要,假如出现几个数相等的情况,但经过离散化之后,他们所储存的值是不相等的,原本位置靠后的快排后位置相较于几个相等的值,它依然靠后,这就保证了一个值更新时不会影响后面和这个值相等的值的读取,举个例子:
比如有这样几个数 :1,2,5,5
离散后 a:1,2,3,4;
更新i=1,2时暂且不谈,
read求和是对a[i]~n;
i=3,ans+read(a[3]) 求和3~n 然后更新3,更新3时,更新的是1~3,也就是小于等于a[3]的
i=4,ans+read(a[4]) 求和4~n 然后更新4,会发现位置3和位置4都是5,但更新时并没有影响
至于add为什么放后面,因为最后一个数的逆序数一定是0,不需要读取,少读取一次
#include <iostream>
#include <iomanip>
#include<stdio.h>
#include<string.h>
#include<stack>
#include<stdlib.h>
#include<queue>
#include<map>
#include<math.h>
#include<algorithm>
#include<vector>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define maxn 500005
using namespace std;
int n;
struct node
{
int val,pos;
}e[maxn];
int t[maxn],a[maxn];
bool cmp(node a,node b)
{
return a.val<b.val;
}
int lowbit(int x)
{
return x&-x;
}
void add(int x,int num)
{
for(int i=x;i>0;i-=lowbit(i))
{
t[i]+=num;
}
}
int read(int x)
{
int sum=0;
for(int i=x;i<=n;i+=lowbit(i))
sum+=t[i];
return sum;
}
int main()
{
while(~scanf("%d",&n),n)
{
mem(t,0);
for(int i=1;i<=n;i++)
{
scanf("%d",&e[i].val);
e[i].pos=i;
}
sort(e+1,e+1+n,cmp);
for(int i=1;i<=n;i++)
a[e[i].pos]=i;
ll ans=0;
for(int i=1;i<=n;i++)
{
ans+=read(a[i]);
//每次加上i~n之间小于a[i]的个数
add(a[i],1);
//更新1~i之间<=a[i]的个数
}
printf("%lld\n",ans);
}
return 0;
}
再敲一遍归并排序的模板
#include <iostream>
#include <iomanip>
#include<stdio.h>
#include<string.h>
#include<stack>
#include<stdlib.h>
#include<queue>
#include<map>
#include<math.h>
#include<algorithm>
#include<vector>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define maxn 500005
using namespace std;
int a[maxn],c[maxn];
ll cnt;
void Merge(int a[],int first,int mid,int last,int c[])
{
int i=first,j=mid+1;
int m=mid,n=last;
int k=0;
while(i<=m||j<=n)
{
if(j>n||(i<=m&&a[i]<=a[j]))
{
c[k++]=a[i++];
}
else
{
c[k++]=a[j++];
cnt+=(m-i+1);
}
}
for(i=0;i<k;i++)
a[first+i]=c[i];
}
void merge_sort(int a[],int first,int last,int c[])
{
if(first<last)
{
int mid=(first+last)/2;
merge_sort(a,first,mid,c);
merge_sort(a,mid+1,last,c);
Merge(a,first,mid,last,c);
}
}
int main()
{
int n;
while(~scanf("%d",&n),n)
{
mem(c,0);
cnt=0;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
merge_sort(a,0,n-1,c);
printf("%lld\n",cnt);
}
return 0;
}