[ SDOI2016 ] 数字配对

题目

Luogu
LOJ
Acwing

思路

001.png

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int N = 410, M = 200010, INF = 1e18;
int n, m, S, T, A[N], B[N], C[N];
int h[N], val[M], ptr[M], f[M], w[M], idx;
void add(int a, int b, int c, int d) { val[idx] = b, f[idx] = c, w[idx] = d, ptr[idx] = h[a], h[a] = idx++; }
void add(int a, int b, int c, int d, int e) { add(a, b, c, e), add(b, a, d, -e); }
bool check(int x, int y) {
    if (x < y) swap(x, y);
    if (x % y != 0 || x == y) return false;
    int t = x / y;
    for (int i = 2; i <= t / i; i++)
        if (t % i == 0) return false;
    return true;
}
int q[N], d[N], pre[M], incf[N], st[N];
// 最大费用最大流
bool SPFA() {
    int hh = 0, tt = 0;
    memset(d, -0x3f, sizeof d), memset(incf, 0, sizeof incf);
    q[tt++] = S, incf[S] = INF, d[S] = 0, st[S] = true;
    while (hh != tt) {
        int t = q[hh++];
        if (hh == N - 1) hh = 0;
        st[t] = false;
        for (int i = h[t], v = val[i]; i != -1; i = ptr[i], v = val[i]) {
            if (f[i] && d[v] < d[t] + w[i]) {
                d[v] = d[t] + w[i], pre[v] = i;
                incf[v] = min(incf[t], f[i]);
                if (st[v]) continue;
                q[tt++] = v, st[v] = true;
                if (tt == N - 1) tt = 0;
            }
        }
    } 
    return incf[T] > 0;
}
int EK() {
    int flow = 0, cost = 0;
    while (SPFA()) {
        int t = incf[T];
        if (cost + d[T] * t < 0) {
            flow += (cost / (-d[T]));
            return flow;
        } else cost += d[T] * t, flow += t;
        for (int i = T; i != S; i = val[pre[i] ^ 1]) 
            f[pre[i]] -= t, f[pre[i] ^ 1] += t;
    }
    return flow;
}
signed main() {
    cin >> n;
    memset(h, -1, sizeof h);
    S = 2 * n + 1, T = n * 2 + 2;
    for (int i = 1; i <= n; i++) cin >> A[i];
    for (int i = 1; i <= n; i++) cin >> B[i];
    for (int i = 1; i <= n; i++) cin >> C[i];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (check(A[i], A[j])) 
                add(i, j + n, INF, 0, C[i] * C[j]);
    
    for (int i = 1; i <= n; i++) add(S, i, B[i], 0, 0);
    for (int i = 1; i <= n; i++) add(n + i, T, B[i], 0, 0);

    cout << EK() / 2 << endl;
    return 0;
}
posted @ 2021-06-12 13:17  Protein_lzl  阅读(40)  评论(0编辑  收藏  举报