loj 3301 「联合省选 2020 A」魔法商店 - 拟阵 - 保序回归
题目传送门
整个联考的区分度主要在会不会保序回归,次要在常数,有毒。。。
关于以下使用的定理和结论的证明以及定义,请自行翻 2018 集训队论文。因为我都不会证。
显然问题是给定一个拟阵 $M$ 和两个基 $I_a$ 以及 $I_b$,定义 $w(I) = \sum_{x\in I} z_x$,要求寻找一组系数 $z_x$,满足 $w(I_a)$ 最小,$w(I_b)$ 最大,并且最小化回归代价 $\sum (z_x - v_x)^2$。
定理1 如果 $I, J$ 都是 $M$ 的独立集,那么交换图 $D_M(I)$ 中存在关于 $I\backslash J$ 以及 $J \backslash I$ 的完美匹配
使用强基交换定理归纳。具体过程见论文。
考虑对于 $I_a -\{x\} + \{y\}$ 得到的新的基,要求满足 $z_x \leqslant z_y$,如果所有都满足这个限制,根据定理1,显然任意一个基都满足 $w(I_a) \leqslant w(I)$。
然后直接贴保序回归的板子就完事了。
Code
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned ll const ll llf = (signed ll) (~0u >> 3); typedef class Edge { public: int ed, nx; ll r; Edge(int ed, int nx, ll r) : ed(ed), nx(nx), r(r) { } } Edge; typedef class MapManager { public: vector<int> h; vector<Edge> E; MapManager(int n) { h.assign(n + 1, -1); E.clear(); } ~MapManager() { h.clear(); E.clear(); } void add_edge(int u, int v, ll r) { E.emplace_back(v, h[u], r); h[u] = (signed) E.size() - 1; } Edge& operator [] (int p) { assert(p < (signed) E.size()); return E[p]; } } MapManager; typedef class Network { public: int S, T; vector<int> cur, div; MapManager g; Network(int S, int T) : S(S), T(T), g(T) { div.resize(T + 1); } void add_edge(int u, int v, ll w) { g.add_edge(u, v, w); g.add_edge(v, u, 0); } bool bfs() { fill(div.begin(), div.end(), 0); queue<int> Q; Q.push(S); div[S] = 1; while (!Q.empty()) { int p = Q.front(); Q.pop(); for (int i = g.h[p]; ~i; i = g[i].nx) { int e = g[i].ed; if (g[i].r && !div[e]) { div[e] = div[p] + 1; Q.push(e); } } } return div[T]; } ll dfs(int p, ll mf) { if (p == T || !mf) { return mf; } ll flow = 0, f; for (int& i = cur[p]; ~i; i = g[i].nx) { int e = g[i].ed; if (div[e] == div[p] + 1 && (f = dfs(e, min(mf, g[i].r))) > 0) { g[i].r -= f; g[i ^ 1].r += f; flow += f; if (!(mf -= f)) break; } } return flow; } ll dinic() { ll ret = 0; while (bfs()) { cur = g.h; dfs(S, llf); } return ret; } vector<bool> get_S() { vector<bool> ret (T + 1, false); queue<int> Q; Q.push(S); ret[S] = true; while (!Q.empty()) { int p = Q.front(); Q.pop(); for (int i = g.h[p]; ~i; i = g[i].nx) { int e = g[i].ed; if (g[i].r && !ret[e]) { ret[e] = true; Q.push(e); } } } return ret; } } Network; const int bzmax = 64; typedef class LinearBasis { public: ull a[bzmax]; void clear() { memset(a, 0, sizeof(a)); } bool insert(ull x, bool chk = false) { for (int i = bzmax; i-- && x; ){ if ((x >> i) & 1) x ^= a[i]; if ((x >> i) & 1) { !chk && (a[i] = x); return true; } } return false; } } LinearBasis; const int N = 1e3 + 3; int n, m; int z[N], v[N]; ull a[N]; vector<int> A, B; void dividing(int l, int r, vector<int> P, vector<pair<int, int>> E, vector<int> org) { if (l == r) { for (auto x : P) { z[org[x]] = l; } return; } if (P.empty()) { return; } auto _P = P; int n = P.size(); vector<int> norg(n); sort(_P.begin(), _P.end()); #define get(x) (lower_bound(_P.begin(), _P.end(), x) - _P.begin()) for (auto& x : P) { int y = org[x]; norg[x = get(x)] = y; } int mid = (l + r) >> 1; Network network (n, n + 1); for (auto& e : E) { e.first = get(e.first); e.second = get(e.second); network.add_edge(e.first, e.second, llf); } for (int x = 0; x < n; x++) { int y = norg[x]; ll dx = ((mid - v[y]) << 1) + 1; if (dx < 0) { network.add_edge(n, x, -dx); } else if (dx > 0) { network.add_edge(x, n + 1, dx); } } network.dinic(); auto inS = network.get_S(); // for (int i = 0; i < n; i++) { // cerr << "(" << norg[i] << ", " << inS[i] << ") "; // } // cerr << '\n'; vector<int> pL, pR; vector<pair<int, int>> eL, eR; for (int i = 0; i < n; i++) { if (inS[i]) { pR.push_back(i); } else { pL.push_back(i); } } for (auto e : E) { int u = e.first, v = e.second; if (inS[u] && inS[v]) { eR.push_back(e); } else if (!inS[u] && !inS[v]) { eL.push_back(e); } } #undef get dividing(l, mid, pL, eL, norg); dividing(mid + 1, r, pR, eR, norg); } LinearBasis lb; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%llu", a + i); } int mi = 1e9, mx = -1; for (int i = 1; i <= n; i++) { scanf("%d", v + i); mi = min(mi, v[i]); mx = max(mx, v[i]); } vector<int> p, org; vector<pair<int, int>> E0; for (int i = 1; i <= n; i++) { p.push_back(i); } org = p; org.insert(org.begin(), 0); A.resize(m); vector<bool> in (n + 1, false); for (auto& x : A) { scanf("%d", &x); in[x] = true; } for (int i = 0; i < m; i++) { lb.clear(); for (int j = 0; j < m; j++) { if (i ^ j) { lb.insert(a[A[j]]); } } for (int p = 1; p <= n; p++) { if (!in[p] && lb.insert(a[p], true)) { E0.emplace_back(A[i], p); // cerr << A[i] << " <= " << p << '\n'; } } } for (auto x : A) { in[x] = false; } B.resize(m); for (auto& x : B) { scanf("%d", &x); in[x] = true; } for (int i = 0; i < m; i++) { lb.clear(); for (int j = 0; j < m; j++) { if (i ^ j) { lb.insert(a[B[j]]); } } for (int p = 1; p <= n; p++) { if (!in[p] && lb.insert(a[p], true)) { E0.emplace_back(p, B[i]); // cerr << p << " <= " << B[i] << '\n'; } } } dividing(mi, mx, p, E0, org); ll ans = 0; for (int i = 1; i <= n; i++) { ans += 1ll * (z[i] - v[i]) * (z[i] - v[i]); } printf("%lld\n", ans); return 0; }