蓝桥集训之火柴排队
-
核心思想:离散化+归并排序
- 由于数据范围较小10w 需要控制时间复杂度到nlogn 同时排两个数组会超时
- 所以将a数组离散化成顺序数组 b数组离散化后再归并排序求逆序对数量
-
#include<iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 100010 , MOD = 99999997; int n; int a[N],b[N],p[N],c[N]; int find(int x) //离散化二分 { int l=1,r=n; while(l<r) { int mid = l+r >>1; if(p[mid] >=x ) r= mid; else l = mid + 1; } return l; } void work(int a[]) //离散化 { for(int i=1;i<=n;i++) p[i] = a[i]; //将原本的a数组存下 仅用于排序 sort(p+1,p+n+1); for(int i=1;i<=n;i++) a[i] = find(a[i]); //更新a数组元素为应该在的下标(根据元素大小) } int merge_sort(int l,int r) //求逆序对数量 { if(l==r) return 0; int mid = l+r >>1; int res = (merge_sort(l,mid) + merge_sort(mid+1,r)); int i = l,j = mid +1,k=0; while(i<=mid && j<=r) { if(b[i] <= b[j]) p[k++] = b[i++]; else p[k++] = b[j++] , res = (res + mid - i + 1) % MOD; } while(i<=mid) p[k++] = b[i++]; while(j<=r) p[k++] = b[j++]; for(int i=l,j=0;i<=r;i++,j++) b[i] = p[j]; return res; } int main() { cin>>n; for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]); work(a),work(b); for(int i=1;i<=n;i++) c[a[i]] = i; //c数组用来保存 对应关系 for(int i=1;i<=n;i++) b[i] = c[b[i]]; //b数组按照 对应关系 更新 cout<<merge_sort(1,n); //b数组归并 return 0; }