CF628F Bear and Fair Set
WanderFreeFish · · 题解
Analysis
首先这道题有特别多的约束条件:
- 分配问题:需要将数字分配到不同的余数类中。
- 整数分配:每个数字要么选,要么不选。
- 容量限制:每个余数类有固定的容量
\frac{n}{5} ,每个前缀区间有固定的容量。
这些条件,尤其是最后一条,可以联想到网络流。
Details
建出超级源点与超级汇点。
首先是把那个“集合的提示”转化成“有恰好
再把每段区间与其中能取到的所有可能值建边。由于每个值只能取到一次(集合的互异性),所以边的最大流量为
然后把所有能取到的值按对
最后把这
连出来就是下面这个东西。
我们需要恰好后面的
Code
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <climits>
#include <utility>
using ll = long long int;
using pii = std::pair <int, int>;
constexpr int MAXN = 1e4 + 10;
struct Dinic {
struct edge {
int v; ll cap; int rev;
edge(int _v, ll _cap, int _rev) : v(_v), cap(_cap), rev(_rev) {}
};
int superS, superT;
std::vector <std::vector <edge> > G;
std::vector <int> dep, lst;
Dinic(int l, int s, int t) : superS(s), superT(t), G(l + 1), dep(l + 1), lst(l + 1) {}
inline void addEdge(int u, int v, ll w) {
G[u].push_back(edge(v, w, G[v].size()));
G[v].push_back(edge(u, 0, G[u].size() - 1));
}
inline bool bfs() {
std::fill(dep.begin(), dep.end(), 0);
std::queue <int> q;
q.push(superS);
dep[superS] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto [v, cap, rev] : G[u]) {
if (dep[v] || cap <= 0) continue;
q.push(v);
dep[v] = dep[u] + 1;
if (v == superT)
return true;
}
}
return false;
}
ll dfs(int u, ll lim) {
if (lim <= 0 || u == superT)
return lim;
ll ret = lim, tot = 0;
for (int& k = lst[u]; k < (int)G[u].size(); k++) {
auto& [v, cap, rev] = G[u][k];
if (cap > 0 && dep[v] == dep[u] + 1) {
ll t = dfs(v, std::min(ret, cap));
ret -= t, tot += t;
cap -= t, G[v][rev].cap += t;
}
if (ret <= 0)
break;
}
return tot;
}
ll maxFlow() {
ll res = 0;
while (bfs()) {
std::fill(lst.begin(), lst.end(), 0);
res += dfs(superS, LLONG_MAX);
}
return res;
}
};
int n, m, q;
pii limit[MAXN];
int l[MAXN], r[MAXN], k[MAXN];
int main() {
std::cin >> n >> m >> q;
for (int i = 1; i <= q; i++)
std::cin >> limit[i].first >> limit[i].second;
limit[++q] = {m, n};
std::sort(limit + 1, limit + 1 + q);
for (int i = 1; i <= q; i++) {
int len = limit[i].first - limit[i-1].first;
int need = limit[i].second - limit[i-1].second;
if (need < 0 || need > len) {
std::cout << "unfair";
return 0;
}
}
int s = m + q + 6, t = m + q + 7;
Dinic net(m + q + 7, s, t);
for (int i = 1; i <= q; i++)
net.addEdge(s, i, limit[i].second - limit[i - 1].second);
for (int i = 1; i <= q; i++) {
for (int j = limit[i - 1].first + 1; j <= limit[i].first; j++)
net.addEdge(i, j + q, 1);
}
for (int i = 1; i <= m; i++)
net.addEdge(i + q, q + m + (i % 5) + 1, 1);
for (int i = 1; i <= 5; i++)
net.addEdge(q + m + i, t, n / 5);
if (net.maxFlow() == n) std::cout << "fair";
else std::cout << "unfair";
return 0;
}