今儿打开51nod
玩了一下
啥都不会
只会写A+B
复习一下归并排序
#include<bits/stdc++.h>
using namespace std;
void merge(int a[],int l1,int r1,int l2,int r2){
int i=l1,j=l2,temp[100],index=0;
while(i<=r1&&j<=r2){
if(a[i]<a[j]){
temp[index++]=a[i++];
}else {
temp[index++]=a[j++];
}
}
while(i<=r1)temp[index++]=a[i++];
while(j<=r2)temp[index++]=a[j++];
for(i=0;i<index;i++){
a[i+l1]=temp[i];
}
}
void mergesort(int a[],int l,int r){
if(l!=r){
int mid=(l+r)/2;
mergesort(a,l,mid);
mergesort(a,mid+1,r);
merge(a,l,mid,mid+1,r);
}
}
int main(){
int n,a[100];
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
cout<<a[i];
}
return 0;
}
归并排序可以上升到逆序对的问题
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
这个题目可以用暴力O(n2)算法,动态规划O(nlogn)
#include<bits/stdc++.h>
using namespace std;
const int N = 500000;
int swap_space[N];//归并排序的交换空间
long long total;//逆序数
void merge(int a[], int begin, int mid,int end){
int i = begin;
int j = mid + 1;
int k = begin;
while(i <= mid && j <= end){
if(a[i] < a[j]){
swap_space[k++] = a[i++];
}else{
swap_space[k++] = a[j++];
total += (mid - i + 1);//total is the reverse count
}
}
while(i <= mid)
swap_space[k++] = a[i++];
while(j <= end)
swap_space[k++] = a[j++];
for(i = begin; i <= end; i++){
a[i] = swap_space[i];
}
}
void mergeSort(int a[], int begin, int end){
if(begin != end){
int mid = (begin + end) / 2;
mergeSort(a,begin, mid);
mergeSort(a,mid+1, end);
merge(a,begin,mid,end);
}
}
int main(){
int n,a[N];
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
mergeSort(a,0,n-1);
cout<<total;
return 0;
}
那么为什么可以用归并来计算逆序对呢?
首先 两个组别的数组之间的元素交换不影响答案,所以在交换过程中累加答案。
其次,两个组别的元素满足这样的关系
a={a1,a2,…},b={b1,b2,…}并且在原数组中满足c={a1,a2,…,b1,b2,…}的顺序
如果a[i]>b[j],则ans+=len(a)-i
eg. a={4,3},b={2,1},c={4,3,2,1}
那么首先对a,b排序
a又变成两个数组
然后排序
于是答案+1
同理b排序,答案+1
于是乎此时a={3,4},b={1,2},c={3,4,1,2}
在应用上面的公式归并排序一遍
答案+2+2
于是答案为6
解答完毕