题目大意:
求使两列数字相差距离最小的交换次数。
思路:
要想使得距离最小,必须让 \(a\) 序列的第 \(k\) 大值与 \(b\) 序列的第 \(k\) 大值处在相同的位置上。
值域是 \(0≤ height \leq 2^{31} - 1\) ,考虑离散化获得第 \(k\) 大的值。
在对 \(a\) 、\(b\) 序列离散化之后,考虑怎样对 \(b\) 进行交换,使得第 \(k\) 大值相对应。
我们构造一个映射关系,使得 \(seq[a[i]] = i\) ,依照这个对应关系,可以得到 \(b\) 目前的对应关系 \(tb = seq[b[i]]\) 。
例如:
seq: 1 2 3 4
a: 1 3 4 2
b: 1 4 2 3
tb: 1 3 4 2
若要使得 \(a\) 、\(b\) 第 \(k\) 大处在相同的位置上,即让 \(seq\) 和 \(tb\) 相等,由于 \(seq\) 是升序排列,则问题最终转化成将原本乱的 \(tb\) 序列升序排列的最少交换次数。
这就是求逆序对的问题,使用树状数组解决。
Code:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const double eps = 1e-6;
const int N = 1e6 + 7;
//#define N 10
const int INF = 0x3f3f3f3f;
const int mod = 1000000007; //998244353
const int dir[8][2] = {0, 1, 0, -1, 1, 0, -1, 0,/* dir4 */ -1, -1, -1, 1, 1, -1, 1, 1};
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll powmod(ll a, ll b) { ll res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
template <typename T> bool ckmin(T &a, const T &b) { return b < a ? a = b, 1 : 0; }
template <typename T> bool ckmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
#define debug(a) cerr << "## " << #a << " = " << a << endl;
constexpr int P = 99999997; //998244353
// assume -P <= x < 2P
int norm(int x) {
if (x < 0) {
x += P;
}
if (x >= P) {
x -= P;
}
return x;
}
template<class T>
T power(T a, int b) {
T res = 1;
for (; b; b /= 2, a *= a) {
if (b % 2) {
res *= a;
}
}
return res;
}
struct Z {
int x;
Z(int x = 0) : x(norm(x)) {}
int val() const {
return x;
}
Z operator-() const {
return Z(norm(P - x));
}
Z inv() const {
assert(x != 0);
return power(*this, P - 2);
}
Z &operator*=(const Z &rhs) {
x = ll(x) * rhs.x % P;
return *this;
}
Z &operator+=(const Z &rhs) {
x = norm(x + rhs.x);
return *this;
}
Z &operator-=(const Z &rhs) {
x = norm(x - rhs.x);
return *this;
}
Z &operator/=(const Z &rhs) {
return *this *= rhs.inv();
}
friend Z operator*(const Z &lhs, const Z &rhs) {
Z res = lhs;
res *= rhs;
return res;
}
friend Z operator+(const Z &lhs, const Z &rhs) {
Z res = lhs;
res += rhs;
return res;
}
friend Z operator-(const Z &lhs, const Z &rhs) {
Z res = lhs;
res -= rhs;
return res;
}
friend Z operator/(const Z &lhs, const Z &rhs) {
Z res = lhs;
res /= rhs;
return res;
}
};
template <typename T>
struct Fenwick {
const int n;
vector<T> a;
Fenwick(int n) : n(n), a(n + 1) {}
void add(int x, T v) {
for (int i = x; i <= n; i += i & -i) {
a[i] += v;
}
}
T sum(int x) {
T ans = 0;
for (int i = x; i > 0; i -= i & -i) {
ans += a[i];
}
return ans;
}
T rangeSum(int l, int r) {
return sum(r) - sum(l);
}
};
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
cin >> n;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
vector<int> lsa(n); // 离散化a
for (int i = 0; i < n; i++) {
lsa[i] = a[i + 1];
}
sort(lsa.begin(), lsa.end());
lsa.erase(unique(lsa.begin(), lsa.end()), lsa.end());
auto getid_a = [&](int x) {
return lower_bound(lsa.begin(), lsa.end(), x) - lsa.begin() + 1;
};
vector<int> seq(n + 1); // change a
for (int i = 1; i <= n; i++) {
seq[getid_a(a[i])] = i;
}
vector<int> lsb(n); // 离散化b
for (int i = 0; i < n; i++) {
lsb[i] = b[i + 1];
}
sort(lsb.begin(), lsb.end());
lsb.erase(unique(lsb.begin(), lsb.end()), lsb.end());
auto getid_b = [&](int x) {
return lower_bound(lsb.begin(), lsb.end(), x) - lsb.begin() + 1;
};
vector<int> tb(n + 1);
for (int i = 1; i <= n; i++) {
tb[i] = seq[getid_b(b[i])];
}
Fenwick<Z> fen(n);
vector<Z> num(n + 1);
for (int i = n; i >= 1; i--) {
num[i] = fen.sum(tb[i]);
fen.add(tb[i], 1);
}
Z ans = 0;
for (int i = 1; i <= n; i++) {
ans += num[i];
}
cout << ans.val() << "\n";
return 0;
}