• 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;
    }
    
  • 相关阅读:
    VUE集成keycloak和Layui集成keycloak
    iscsi基本命令
    Linux网卡bond模式
    Unmount and run xfs_repair
    Centos7 升级过内核 boot分区无法挂载修
    Centos7 误删除bin/sbin之类的恢复
    QSS 记录
    #pragma 小节
    解决Github打不开问题
    判断数据是否在指定区间内
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/15999939.html
Copyright © 2020-2023  润新知