洛谷 P1966 火柴排队

题目描述

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:(aibi)2

其中ai 表示第一列火柴中第ii个火柴的高度,bi表示第二列火柴中第 ii 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997取模的结果。

输入输出格式

输入格式:

共三行,第一行包含一个整数n,表示每盒中火柴的数目。

第二行有n个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。

第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式:

一个整数,表示最少交换次数对 99,999,997 取模的结果。

输入输出样例

输入样例#1: 
4
2 3 1 4
3 2 1 4
输出样例#1: 
1
输入样例#2: 
4
1 3 4 2
1 7 2 4
输出样例#2: 
2

说明

【输入输出样例说明1】

最小距离是0,最少需要交换 1 次,比如:交换第 1列的前2 根火柴或者交换第 2 列的前 2根火柴。

【输入输出样例说明2】

最小距离是 10,最少需要交换2次,比如:交换第1列的中间2根火柴的位置,再交换第2 列中后 2 根火柴的位置。

【数据范围】

对于 10%的数据, 1 ≤ n ≤ 10

对于 30%的数据,1 ≤ n ≤ 100

对于 60%的数据,1 ≤ n ≤ 1,000

对于 100%的数据,1 ≤ n ≤ 100,000,0≤火柴高度≤ maxlongint

解题思路:

看样例和题目,我们会发现这道题从人类的思维考虑并不难,只需将大的靠大的,小的靠小的即可.

但我们需要将其转化为机器可以理解的思维:我们将第一个序列离散化后按照输入顺序定义为1~n(也就是说原来序列的数字已经不是我们日常认知里的数字了,而是我们新定义的数字),将第二个序列离散化,将离散化后的序列按照第一个序列的对应关系转化为我们新定义的数字,求逆序对个数,即为答案.

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm> 
 4 #include<map>
 5 #define lowbit(k) k & -k
 6 
 7 using namespace std;
 8 
 9 long long n,a[100001],b[100001],c[100001],d[100001],e[100001]; 
10 map<int,int > l;
11 
12 inline void Discretization2() {
13     sort(d+1,d+n+1);
14     unique(d+1,d+1+n) - (d + 1);
15     for(int i = 1;i <= n; i++) c[i] = lower_bound(d+1,d+1+n,c[i]) - d;
16 }
17 
18 void Discretization() {//离散化 
19     sort(b+1,b+n+1);
20     unique(b+1,b+1+n) - (b + 1);
21     for(int i = 1;i <= n; i++) a[i] = lower_bound(b+1,b+1+n,a[i]) - b;
22 } 
23 
24 inline void jia(int x,int y) {
25     while(x <= n) {
26         e[x] += y;
27         x += lowbit(x);
28     }
29 }
30 
31 int sum(int x) {
32     long long p = 0;
33     for(int i = x;i > 0; i -= lowbit(i)) p += e[i];
34     return p; 
35 }
36 
37 int main()
38 {
39     scanf("%lld",&n);
40     for(int i = 1;i <= n; i++) {
41         scanf("%lld",&a[i]);
42         b[i] = a[i];
43     } 
44     Discretization();
45     for(int i = 1;i <= n; i++) {
46         scanf("%lld",&c[i]);
47         d[i] = c[i];
48         l[a[i]] = i;
49     }
50     Discretization2();
51     for(int i = 1;i <= n; i++) 
52         c[i] = l[c[i]];
53     long long ans = 0;
54     for(int i = n;i > 0; i--) {//树状数组求逆序对个数 
55         jia(c[i],1);
56         ans += sum(c[i]-1);
57     }
58     printf("%lld",ans%99999997);//千万要%99999997,不然只能得80分 
59     return 0;
60 }

//NOIP2013提高 day1 t2

 

猜你喜欢

转载自www.cnblogs.com/lipeiyi520/p/10853956.html
今日推荐