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;
}
浙公网安备 33010602011771号