归并排序及应用
void merge_sort(int *s,int l,int h,int *t) //t辅助数组 { if(h-l>1){ int mid = l+(h-l)/2; int i=l,p=l,q=mid; merge_sort(s,l,mid,t); merge_sort(s,mid,h,t); while(p<mid||q<h){ if(q>=h||(p<mid&&s[p]<=s[q])) t[i++]=s[p++]; else t[i++]=s[q++]; } } for(int i=l;i<h;i++) s[i]=t[i]; } int main() { int s[10]={10,3,5,2,1,4,8,6,9,7},t[10]={10,3,5,2,1,4,8,6,9,7}; for(int i=0;i<10;i++) printf(i==9?"%d\n":"%d ",s[i]); merge_sort(s,0,10,t); for(int i=0;i<10;i++) printf(i==9?"%d\n":"%d ",s[i]); return 0; }
逆序对问题,给出一个序列,求逆序对数,及有多少个又需对(i,j)是的i<j但ai>aj。n高达10e6
可以种归并排序求解,或者也可以用树状数组。
int c; void merge_sort(int *s,int l,int h,int *t) //t辅助数组 { if(h-l>1){ int mid = l+(h-l)/2; int i=l,p=l,q=mid; merge_sort(s,l,mid,t); merge_sort(s,mid,h,t); while(p<mid||q<h){ if(q>=h||(p<mid&&s[p]<=s[q])) t[i++]=s[p++]; else t[i++]=s[q++],c+=mid-p; } } for(int i=l;i<h;i++) s[i]=t[i]; } int main() { int s[10]={6,7,8,9,10,1,2,3,4,5},t[10]={6,7,8,9,10,1,2,3,4,5}; for(int i=0;i<10;i++) printf(i==9?"%d\n":"%d ",s[i]); merge_sort(s,0,10,t); for(int i=0;i<10;i++) printf(i==9?"%d\n":"%d ",s[i]); printf("%d\n",c); return 0; }
应用:
考分鄙视(exam)
时间限制: 1 Sec 内存限制: 64 MB
提交: 15 解决: 5
[提交][状态][讨论版]
题目描述
Whence这个学期考了n次试,每一次都有一个0~20000之间的整数分数。Whence本来的状态应该是每一次考试都比前一次多一分(除第一次), 但由于他很不稳定,偏差可能很大。对于第i次考试,如果有第j次考试满足l≤j<i≤n,且以第j次考试分数作为基准估计的第i次考试成绩比实际成 绩低,就说第i次考试鄙视了第j次考试(估计分可以超过20000)。为了提高自信,Whence想知道他这个学期所有考试总共有多少次鄙视。
输入
第1行n (l<n≤100000);
第2行为n次考试成绩。
输出
1行,这个学期所有考试的总共鄙视次数(总数可能很大,只需要输出总数mod 12345的值)。
样例输入
4
1 3 3 5
样例输出
3
提示
样例说明:第一次考试的分数是1,那么估计应该是第二次为2,第三次为3,第四次为4, 但第二次实际分数为3,比2大,这是1次鄙视;第四次实际分数为5,比估计的4大,这也是1次鄙视;第二次考试的分数是3,那么估计应该是第三次为4,第 四次为5,实际分数分别是3和5,所以没有鄙视;第三次考试的分数为3,那么估计第四次是4,但实际为5,这又是1次鄙视。因此总鄙视次数为3次。
分析:当i-j<s[i]-s[j]受到鄙视,即s[j]-j<s[i]-i受到鄙视。 把数组倒置。 即求逆序对。。
#include <cstring> #include <vector> #include <cstdio> #include <algorithm> #include <queue> #define fi first #define se second #define pi pair<int,int> #define md make_pair #define ha pair<int,pair<int,pi> > using namespace std; const int inf=0x3f3f3f3f; int c,s[100010],t[100010]; void merge_sort(int *s,int l,int h,int *t) //t辅助数组 { if(h-l>1){ int mid = l+(h-l)/2; int i=l,p=l,q=mid; merge_sort(s,l,mid,t); merge_sort(s,mid,h,t); while(p<mid||q<h){ if(q>=h||(p<mid&&s[p]<=s[q])) t[i++]=s[p++]; else t[i++]=s[q++],c=(c+mid-p)%12345; } } for(int i=l;i<h;i++) s[i]=t[i]; } int main() { //freopen("data.in","r",stdin); int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",s+i),s[i]-=i,t[i]=s[i]; reverse(s+1,s+n+1); reverse(t+1,t+n+1); //for(int i=1;i<=n;i++)printf("%d ",s[i]);printf("\n"); merge_sort(s,1,n+1,t); //for(int i=1;i<=n;i++)printf("%d ",s[i]);printf("\n"); printf("%d\n",c); return 0; }