您的位置:首页 > 其它

ural1090 逆序对(归并排序和树状数组)

2017-11-11 13:56 417 查看
题意:

在军队中

军官命令新兵排行成列。新兵们排成了K行,每行有N人。但有K人没有排在正确的位置上。

正确的排队位置如下:第一个士兵必须是最高的,第二个是第二高的,依此类推,最后一个士兵必须是最矮的。为了排好队,军官规定每一个士兵,如果与他同一排的前一个人比他矮,那么他就向前跳一步。

注意没有两个新兵的身高相同。

军官想找出哪一排士兵跳的总次数最多,好惩罚他们到厨房去工作。你的目标就是帮助军官找到这一排。

 

Input

输入的第一行包含了两个数N和K(2≤N≤10000,1≤K≤20)。接下来的K行每行包含N个整数。新兵已经按照身高编好了号(1号最高,N号最矮)。每一行是相应的一排,例如某一行的第一个整数代表这行的第一个人等等。

 

Output

输出跳跃次数最多的那一行的编号。如果有几行次数相同,则输出行编号最小的那个。

是在个人训练赛的时候遇到的一道签到题,求逆序对如果枚举的话时间复杂度是n^2,太大了。一般我们用于求逆序对的方法有两种,一种是归并排序,一种是树状数组。归并排序的代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
const int maxn=10000+20;
const int maxk=25;
int G[maxk][maxn];
int n,k,num ;
int t[maxn];
int a[maxn];
void merge_sort(int *A,int L,int R,int *T){
if(R-L==0)return ;
int m=L+(R-L)/2;
merge_sort(A,L,m,T);
merge_sort(A,m+1,R,T);
int p=L,q=m+1,i=L;
while(p<=m||q<=R){
if((A[p]<A[q]&&p<=m)||q>R)T[i++]=A[p++];
else{
T[i++]=A[q++];
num+=m-p+1;
}

}
for(int i=L;i<=R;i++)A[i]=T[i];
}

int main(){
cin>>n>>k;
int ans=-1,ansn=-1;
for(int i=1;i<=k;i++){
for(int j=1;j<=n;j++){
cin>>G[i][j];
}
num=0;
merge_sort(G[i],1,n,t);
if(ans<num){
ans=num;ansn=i;
}
}
cout<<ansn;
return 0;
}

这种方法是本来就会的一种方法,很快写完A掉了,但是从来没有尝试过用树状数组来求逆序对。一开始思维受限于归并的方法,一直在考虑树状数组里存的内容是什么,后来想到,直接把每个数字树状数组作为下标对于每个数字a,通过树状数组求得比a小的数字有多少。但是发现,因为要直接以每个数字a的值作为树状数组的下标,所以···开不下,于是想了另一种办法,用一个结构体来保存每个数字的值,并给他们重新排序,给每个值赋予一个编号mval,mval的范围位1-n,这样便可以解决此问题了(查资料了解到这个方法叫离散化,而我离散化的写法非常白痴#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;
const int maxn=10000+10;
const int maxk=25;
struct Num{
int val,mval,i;
}num[maxn];
int G[maxn],C[maxn] ;
int n,k;
int lowbit(int x){return x&-x;}
int sum(int x){
int ans=0;
while(x>0){
ans+=C[x];
x-=lowbit(x);
}
return ans;
}
int add(int x){
while(x<=n){
C[x]+=1;
x+=lowbit(x);
}
}
int cmp1(Num a,Num b){
return a.val<b.val;
}
int cmp2(Num a,Num b){
return a.i<b.i;
}
int main(){
cin>>n>>k;
int ans=-1,ansn=-1;
for(int i=1;i<=k;i++){
int ANS=0;
memset(C,0,sizeof(C));
for(int j=1;j<=n;j++){
cin>>num[j].val;
num[j].i=j;
}

sort(num+1,num+1+n,cmp1);
for(int j=1;j<=n;j++)
num[j].mval=j;
sort(num+1,num+1+n,cmp2);
for(int j=1;j<=n;j++){
int a=num[j].mval;
add(a);
ANS+=(j-sum(a));
}
/*cin>>G[i][j];
add(G[i][j]);
ANS+=(j-sum(G[i][j]));*/
//cout<<num<<endl;
if(ans<ANS){
ans=ANS,ansn=i;
}
}
cout<<ansn;

return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: