1. 程式人生 > 其它 >Luogu P1966 火柴排隊(樹狀陣列、離散化)

Luogu P1966 火柴排隊(樹狀陣列、離散化)

P1966 火柴排隊

題目大意:

求使兩列數字相差距離最小的交換次數。

思路:

要想使得距離最小,必須讓 \(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;
}