蓝桥集训之小朋友排队
-
核心思想:归并排序
- 可证明每个小朋友交换的次数为 左边比他高的人数 + 右边比他低的人数
- 所以求出上述值 再k*(k+1)/2 求和即可
- 简化为用归并排序求人数
-
#include<iostream> #include<algorithm> #include<cstring> #define x first #define y second using namespace std; const int N = 100010; typedef long long LL; typedef pair<int,int> PII; PII q[N],t[N]; int n; int sum[N]; LL res; void merge_sort(int l,int r) { if(l==r) return; int mid = l+r >>1; merge_sort(l,mid) , merge_sort(mid+1,r); int i = l,j = mid + 1,k=0; while(i<=mid && j <= r) { if(q[i] <= q[j]) { sum[q[i].y] += j - mid -1; //当q[i]<=q[j]时 因为左右区间都已经排好序 则mid+1 - j 的所有数都比q[i]要小 加的是后面小的数 t[k++] = q[i++]; } else { sum[q[j].y] += mid - i + 1; //i - mid的所有数都比q[j]要大 加的是前面大的数 t[k++] = q[j++]; } } while(i<=mid) { sum[q[i].y] += j - mid -1; //说明q[i]剩的都是最大的 mid+1 - j的所有数都比它小 t[k++] = q[i++]; } while(j<=r) t[k++] = q[j++]; //说明q[j]剩最大的 不用加 for(int i=l,j=0;i<=r;i++,j++) q[i] = t[j]; return ; } int main() { cin>>n; for(int i=0;i<n;i++) cin>>q[i].x,q[i].y = i; //x记录数值 y记录下标 merge_sort(0,n-1); for (int i = 0; i < n; i ++ ) res += (LL)sum[i] * (sum[i] + 1) / 2; cout<<res; }