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,太大了。一般我们用于求逆序对的方法有两种,一种是归并排序,一种是树状数组。归并排序的代码如下:
这种方法是本来就会的一种方法,很快写完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;
}
)
在军队中
军官命令新兵排行成列。新兵们排成了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;
}
)
相关文章推荐
- 1090. In the Army Now (Ural 1090 归并排序||树状数组)
- 逆序对的两种解法(归并排序和树状数组)及其变种问题的一点思考
- URAL - 1090 树状数组求逆序数
- poj 2299 Ultra-QuickSort 求逆序对,树状数组和归并排序
- HDU 3743 Frosh Week(树状数组或归并排序求逆序)
- 求逆序对数的NLogN解法:归并排序、树状数组和线段树
- poj-2299-Ultra-QuickSort-归并排序求逆序数--或树状数组
- POJ_3067 Japan[ 逆序数 树状数组 or 归并排序)
- poj 2299 树状数组+离散化 or 归并排序 求逆序对
- 求逆序对数的NLogN解法:归并排序、树状数组和线段树
- 求逆序对数的方法(归并排序 and 树状数组)
- POJ Ultra-QuickSort 逆序数 树状数组 归并排序
- POJ 2299 Ultra-QuickSort 求逆序对数(归并排序,树状数组)
- POJ 2299 Ultra-QuickSort(求逆序数,归并排序或者离散化+树状数组)
- 树状数组 --- (离散化+树状数组、求逆序对)
- hash一下 + 归并排序计算逆序对数
- 关于归并排序及快速求序列逆序对数的学习
- NYOJ 117 求逆序数 【树状数组】或【归并排序】
- 【归并排序】【逆序数】HDU 5775 Bubble Sort
- 数据结构实验之排序五:归并求逆序数【归并排序】