【归并】火柴排序

传送门:CodeVS3286

2013NOIP提高组的题


很显然如果a中第i大的与b中第i大的对应,那么结果最优

由于同组中个不相同,排序+map可以轻松实现对应

这样就能求出序列q,其中$q_i$表示$a_i$放在$q_i$位时能与$b_i$对应

然后找出q中的逆序对个数(取模),即为答案。


代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define mo 99999997
int n,ans;
int a[100030],b[100030],aa[100030],bb[100030],t[100030],p[100030],q[100030];
map<int,int> m_a,m_b;
int merge(int l,int r){
if (l==r) return 0;
int mid=(l+r)>>1;
int sum=(merge(l,mid)+merge(mid+1,r))%mo;
int j=mid+1;
for (int i=l;i<=mid;i++){
while (j<=r && q[i]>q[j])
j++;
sum=(sum+j-mid-1)%mo;
}
int xb=l;
j=mid+1;
for (int i=l;i<=mid;i++){
while (j<=r && q[i]>q[j]){
t[xb]=q[j];
xb++;
j++;
}
t[xb]=q[i];
xb++;
}
while (j<=r){
t[xb]=q[j];
xb++;
j++;
}
for (int i=l;i<=r;i++) q[i]=t[i];
return sum%mo;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),aa[i]=a[i];
for (int i=1;i<=n;i++) scanf("%d",&b[i]),bb[i]=b[i];
sort(aa+1,aa+n+1); sort(bb+1,bb+n+1);
for (int i=1;i<=n;i++)
m_b[bb[i]]=i;
for (int i=1;i<=n;i++)
p[m_b[b[i]]]=i;
for (int i=1;i<=n;i++)
m_a[aa[i]]=i;
for (int i=1;i<=n;i++)
q[i]=p[m_a[a[i]]];
ans=merge(1,n);
printf("%d\n",ans);
return 0;
}