AcWing 505. 火柴排队
原题链接
中等
作者:
无双飞怪
,
2024-04-18 20:17:46
,
所有人可见
,
阅读 1
// 原数组:30 10 20 50 40
// p:2 3 1 5 4//最小的数在下标为2的位置 第二大的数在下标为3的位置……
// a: 3 1 2 5 4
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010,MOD=99999997;
int n;
int a[N],b[N],c[N],p[N];
int tmp[N];
long long res=0;
void work(int a[])
{
//离散化的含义:在1~n中保持原数组中的1~N的相对顺序不变
for(int i=0;i<n;i++) p[i]=i;
sort(p,p+n,[&](int x,int y){return a[x]<a[y];});
for(int i=0;i<n;i++) a[p[i]]=i;
//这一步没啥意义 就是把排好序的值映射成下标(数组里装的是值 数组的值是下标)
}
long long merge(int l,int r)
{
if(l>=r) return 0;
int mid=l+r>>1;
long long res=(merge(l,mid)+merge(mid+1,r))%MOD;
int i=l,j=mid+1,k=0;
while(i<=mid&&j<=r)
{
if(b[i]<=b[j]) tmp[k++]=b[i++];//这里注意是<=而不是<
else tmp[k++]=b[j++],res=(res+mid-i+1)%MOD;//注意这里要取模
}
while(i<=mid) tmp[k++]=b[i++];
while(j<=r) tmp[k++]=b[j++];
for(int i=l,j=0;i<=r;i++,j++)
{
b[i]=tmp[j];
}
return res;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<n;i++) scanf("%d",&b[i]);
work(a),work(b);//离散化 注:work中只是两步独立的离散化
for(int i=0;i<n;i++) c[a[i]]=i;
for(int i=0;i<n;i++) b[i]=c[b[i]];
//这里注意是c不是b
//用a取排b 在这里我们假定a是有序的 就这么排b b中肯定有与a相对顺序不一样的 此为逆序对
cout<<merge(0,n-1);//最少的排序次数即为逆序对数(因为每次排序最多只能让逆序对数减少1)
return 0;
}