P1966 [NOIP 2013 提高组] 火柴排队 解题报告
题目链接
题意
涵涵有两盒火柴,每盒装有 \(n\) 根火柴,每根火柴都有一个
高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:$ \sum (a_i-b_i)^2$。
其中 \(a_i\) 表示第一列火柴中第 \(i\) 个火柴的高度,\(b_i\) 表示第二列火柴中第 \(i\) 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 \(10^8-3\) 取模的结果。
对于 \(100\%\) 的数据,\(1 \leq n \leq 10^5\),\(0 \leq a_i,b_i < 2^{31}\) 且对于任意 \(1\le i<j\le n\),\(a_i\neq a_j\),\(b_i\neq b_j\)。
思路
首先注意到当 \(a\) 和 \(b\) 都从小到大排一一对应是最优的。
然后考虑如何使每根火柴一一对应。
手玩一下不难发现交换次数是逆序对。
然后用树状数组求逆序对就可以了。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, mod = 1e8 - 3;
struct node
{
int id, a;
}a[N], b[N];
int n, w[N], ans, pre[N];
int lowbit(int x)
{
return x & (-x);
}
bool cmp(node a, node b)
{
return a.a < b.a;
}
void update(int x)
{
for(; x <= n; x += lowbit(x))
{
w[x] ++;
}
}
int query(int x)
{
int cnt = 0;
for(; x != 0; x -= lowbit(x))
{
cnt += w[x];
}
return cnt;
}
signed main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
cin >> a[i].a;
a[i].id = i;
}
for(int i = 1; i <= n; i ++)
{
cin >> b[i].a;
b[i].id = i;
}
sort(a + 1, a + n + 1, cmp);
sort(b + 1, b + n + 1, cmp);
for(int i = 1; i <= n; i ++)
{
pre[a[i].id] = b[i].id;
}
for(int i = 1; i <= n; i ++)
{
ans = (ans + i - 1 - query(pre[i]))% mod;
update(pre[i]);
}
cout << ans << endl;
}

浙公网安备 33010602011771号