Luogu P10918 小分图最大匹配
我的博客。
首先考虑连边的情况。
可以把
于是就可以把
考虑左部点
具体就是令
于是一个想法就是对于右部点
为什么是
于是接下来就考虑如何算左部点
官方题解用了个莫反,是不是太唐了点。
实际上这个值就是
那么
那么接下来就可以考虑网络流了。
因为此时右部点都是挂在左部点上的,所以不用建成一个二分图的形式。
具体的,对于左部点
同时对于左部点
一个想法是对于任意一个质数
然后跑网络流即可。
复杂度
其中
#include<bits/stdc++.h>
using ll = long long;
constexpr ll inf = 1e18;
const int maxN = 7e3 + 10, maxM = maxN + maxN + maxN * 12;
ll val[maxM * 2];
int to[maxM * 2], nxt[maxM * 2], fir[maxN], tot = 1;
int S, T;
inline void add(int x, int y, ll w, bool f = 1) {
to[++tot] = y, val[tot] = w, nxt[tot] = fir[x], fir[x] = tot;
if (f) add(y, x, 0, 0);
}
int hd[maxN], dep[maxN];
inline bool bfs() {
for (int i = 1; i <= T; i++)
hd[i] = fir[i], dep[i] = -1;
dep[S] = 0;
std::queue<int> Q; Q.push(S);
while (! Q.empty()) {
int u = Q.front(); Q.pop();
if (u == T) return true;
for (int i = hd[u]; i; i = nxt[i])
if (dep[to[i]] == -1 && val[i])
dep[to[i]] = dep[u] + 1, Q.push(to[i]);
}
return false;
}
inline ll dfs(int u, ll fl) {
if (u == T)
return fl;
ll ud = 0;
for (int &i = hd[u]; i; i = nxt[i])
if (dep[u] + 1 == dep[to[i]] && val[i]) {
ll k = dfs(to[i], std::min(fl - ud, val[i]));
if (! k) dep[to[i]] = -1;
ud += k, val[i] -= k, val[i ^ 1] += k;
if (ud == fl)
return fl;
}
return ud;
}
inline ll Dinic() {
ll ans = 0, f;
while (bfs())
while ((f = dfs(S, inf)) > 0)
ans += f;
return ans;
}
const int maxn = 7e3 + 10;
std::map<ll, int> id;
ll res[maxn], cnt[maxn];
std::vector<ll> pr;
inline void initpr(ll m) {
for (ll x = 2; x * x <= m; x++)
if (m % x == 0) {
pr.push_back(x);
while (m % x == 0) m /= x;
}
if (m > 1)
pr.push_back(m);
}
inline ll phi(ll x) {
ll v = x;
for (ll p : pr)
if (x % p == 0)
v /= p, v *= p - 1;
return v;
}
int main() {
int n; ll m; scanf("%d%lld", &n, &m);
for (ll i = 1; i * i <= m; i++)
if (m % i == 0)
id[i] = id[m / i] = 0;
initpr(m);
int N = 0;
for (auto &[x, c] : id)
c = ++N, res[N] = x;
for (ll a, c; n--; )
scanf("%lld%lld", &a, &c), cnt[id[std::__gcd(a, m)]] += c;
S = N + 1, T = N + 2;
for (int i = 1; i <= N; i++) {
add(S, i, cnt[i]);
add(i, T, phi(m / res[i]));
}
for (int i = 1; i <= N; i++)
for (ll p : pr)
if (res[i] % p == 0)
add(id[res[i] / p], i, inf);
printf("%lld\n", Dinic());
return 0;
}