Frosh Week
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2677 Accepted Submission(s): 888
Problem Description
During Frosh Week, students play various fun games to get to know each other and compete against other teams. In one such game, all the frosh on a team stand in a line, and are then asked to arrange themselves according to some criterion, such as their height, their birth date, or their student number. This rearrangement of the line must be accomplished only by successively swapping pairs of consecutive students. The team that finishes fastest wins. Thus, in order to win, you would like to minimize the number of swaps required.
Input
The first line of input contains one positive integer n, the number of students on the team, which will be no more than one million. The following n lines each contain one integer, the student number of each student on the team. No student number will appear more than once.
Output
Output a line containing the minimum number of swaps required to arrange the students in increasing order by student number.
Sample Input
3 3 1 2
Sample Output
2
首先,这道题实质是求逆序数(最小步数排成一队->逆序数(在只能相邻交换的情况下成立,如果能跨越,就不是求逆序数了!2016.3.20 蓝桥杯省赛));其次这道题目的本质思想是把原数组a映射到另一个数组的下标,然后每放入一个,查找在它后面的数有几个,这个个数就是此位置逆序数,由于暴力查找效率过低使用树状数组维护这一个数组,便于得到前缀和,这个位置的逆序数就是getsum(n)-getsum(a[i].num);另外一个问题是:原数组跨度可能非常大,为了优化空间复杂度,使用离散化(只适用于只关注数据相对大小,不关注具体值的情况),这里还使用了一个小技巧:给数组的每个元素一个id,因为sort函数会改变原数组的相对位置,所以改变之后可以根据id恢复回来;最后扫描一下就可以了,注意逆序数需要long long保存。
/*------------------Header Files------------------*/
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <ctype.h>
#include <cmath>
#include <stack>
#include <queue>
#include <map>
#include <vector>
#include <limits.h>
using namespace std;
/*------------------Definitions-------------------*/
#define LL long long
#define PI acos(-1.0)
#define INF 0x3F3F3F3F
#define MOD 10E9+7
#define MAX 1000050
/*---------------------Work-----------------------*/
struct node
{
int id,num;
}a[MAX];
int tree[MAX],n;
LL cnt; //逆序对计数
bool cmp1(node a,node b)
{
return a.num<b.num;
}
bool cmp2(node a,node b)
{
return a.id<b.id;
}
int lowbit(int i)
{
return i&-i;
}
void update(int i,int num)
{
while(i<=n)
{
tree[i]+=num;
i+=lowbit(i);
}
}
int getsum(int i)
{
int sum=0;
while(i>=1)
{
sum+=tree[i];
i-=lowbit(i);
}
return sum;
}
void work()
{
while(scanf("%d",&n)==1)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].num);
a[i].id=i;
}
sort(a+1,a+n+1,cmp1);
for(int i=1;i<=n;i++) //离散化处理
a[i].num=i; //不会出现重复数字的情况
sort(a+1,a+n+1,cmp2); //恢复原来顺序
memset(tree,0,sizeof(tree));
cnt=0;
//for(int i=1;i<=n;i++)
// printf("%d ",a[i].num);
for(int i=1;i<=n;i++)
{
update(a[i].num,1);
cnt+=getsum(n)-getsum(a[i].num);
}
//for(int i=1;i<=n;i++)
// printf("%d\n",tree[i]);
printf("%I64d\n",cnt);
}
}
/*------------------Main Function------------------*/
int main()
{
//freopen("test.txt","r",stdin);
//freopen("cowtour.out","w",stdout);
//freopen("cowtour.in","r",stdin);
work();
return 0;
}