Luogu P1966 火柴排队(树状数组、离散化)

P1966 火柴排队

题目大意:

求使两列数字相差距离最小的交换次数。

思路:

要想使得距离最小,必须让 a 序列的第 k 大值与 b 序列的第 k 大值处在相同的位置上。

值域是 0height2311 ,考虑离散化获得第 k 大的值。

在对 ab 序列离散化之后,考虑怎样对 b 进行交换,使得第 k 大值相对应。

我们构造一个映射关系,使得 seq[a[i]]=i ,依照这个对应关系,可以得到 b 目前的对应关系 tb=seq[b[i]]

例如:

Copy
seq: 1 2 3 4 a: 1 3 4 2 b: 1 4 2 3 tb: 1 3 4 2

若要使得 abk 大处在相同的位置上,即让 seqtb 相等,由于 seq 是升序排列,则问题最终转化成将原本乱的 tb 序列升序排列的最少交换次数。

这就是求逆序对的问题,使用树状数组解决。

Code:
Copy
#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; }
posted @   Nepenthe8  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示