题意:求逆序数对。输出逆序数对最大的一行的标号,若有多行,输出其中行数最小的一行的标号。
方法一:划分区间,由于每个数的范围都是1-N。肯定小于10000.
将10000分成100个区间,记录1-10000每个值有几个,再记录每个区间内有几个。
对于每个值,只要知道它之前的数中有多少个比它大就行了
每次搜索最多100个区间+100个值 =200次.
方法二:归并排序顺便求逆序数对。
方法一代码:
int ALL,ANS,tempA; int h[10101]; int Ih[102]; int N,K; int main(void) { while(cin>>N>>K){ ALL=-1;ANS=1; for(int i=0;i<K;i++){ memset(h,0,sizeof(h));memset(Ih,0,sizeof(Ih)); tempA=0; for(int j=0;j<N;j++){ int temp; scanf("%d",&temp); for(int i=temp;i<temp/100*100+100;i++) tempA+=h[i]; for(int i=temp/100+1;i<=101;i++) tempA+=Ih[i]; h[temp]++;Ih[temp/100]++; } if(~ALL) { if(tempA>ALL) ALL=tempA,ANS=i+1; } else ALL=tempA,ANS=i+1; } cout<<ANS<<endl; } return 0; }
int R[20][10000]; int N,K; int rank[10000]; int merge(int a[],int lo,int hi){ if(lo>=hi) return 0; int mid=lo+(hi-lo)/2,ANS=0; ANS+=merge(a,lo,mid); ANS+=merge(a,mid+1,hi); int *b=new int[mid-lo+1]; int *c=new int[hi-mid]; for(int i=0;i<mid-lo+1;i++) b[i]=a[lo+i]; for(int i=0;i<hi-mid;i++) c[i]=a[i+mid+1]; int Ib=0,Ic=0,Ia=0; while(Ia<hi-lo+1){ if(Ib <mid-lo+1&&Ic < hi-mid){ if(b[Ib]>c[Ic]) a[lo+Ia++]=c[Ic++],ANS+=mid-lo+1-Ib; else a[lo+Ia++]=b[Ib++]; } else if(Ib <mid-lo+1){ a[lo+Ia++]=b[Ib++]; } else if(Ic<hi-mid){ a[lo+Ia++]=c[Ic++]; } } delete []b; delete []c; return ANS; } int main(void) { while(cin>>N>>K){ for(int i=0;i<K;i++){ for(int j=0;j<N;j++){ scanf("%d",&R[i][j]); } } int ANS=merge(R[0],0,N-1);int ANSI=0; for(int i=0;i<K;i++){ int D=merge(R[i],0,N-1); if(D >ANS) ANS=D,ANSI=i; } cout<<ANSI+1<<endl; } return 0; }