目录

P4068-[SDOI2016]数字配对

P4068-[SDOI2016]数字配对

题目:

题目描述:

有 n 种数字,第 i 种数字是 $a_i$、有 $b_i$ 个,权值是 $c_i$。

若两个数字 $a_i$、$a_j$ 满足,$a_i$ 是 $a_j$ 的倍数,且 $a_i/a_j$ 是一个质数,

那么这两个数字可以配对,并获得 $c_i \times c_j$ 的价值。

一个数字只能参与一次配对,可以不参与配对。

在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

输入格式:

第一行一个整数 n。

第二行 n 个整数 $a_1,a_2,\cdots,a_n$。

第三行 n 个整数 $b_1,b_2,\cdots,b_n$。

第四行 n 个整数 $c_1,c_2,\cdots,c_n$。

输出格式:

一行一个数,最多进行多少次配对

样例:

样例输入 1:

1
2
3
4
3
2 4 8
2 200 7
-1 -2 1

样例输出 1:

1
4

思路:

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "ybwhead/ios.h"
#define int long long
int n;
const int maxn = 2e2 + 10;
const int maxm = 5e5 + 10;
const long long inf = 0x3f3f3f3f3f3f3f3f;
int a[maxn], b[maxn], c[maxn];
int tot = 1, head[maxn];
struct edge
{
    int u, v, nxt;
    long long w, x;
} e[maxm];
void __ADD(int u, int v, long long w, int x)
{
    e[++tot] = (edge){u, v, head[u], w, x};
    head[u] = tot;
}
void add(int u, int v, long long w, int x)
{
    __ADD(u, v, w, x);
    __ADD(v, u, 0, -x);
}
int S, T;
int prime(int n)
{
    int x = 0;
    for (int i = 2; i * i <= n; i++)
    {
        while (n % i == 0)
            x++, n /= i;
    }
    if (n > 1)
        return x + 1;
    return x;
}
int cnt[maxn];
long long dis[maxn];
queue<int> q;
int vis[maxn];
int frm[maxm];
int bfs()
{
    for (int i = 0; i <= n + 1; i++)
        vis[i] = 0, dis[i] = -inf;
    q.push(S);
    dis[S] = 0;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u]; i; i = e[i].nxt)
        {
            int v = e[i].v;
            if (e[i].w && dis[u] + e[i].x > dis[v])
            {
                dis[v] = dis[u] + e[i].x;
                frm[v] = i;
                if (!vis[v])
                    q.push(v), vis[v] = 1;
            }
            // yout << e[i].v << ' ' << e[i].u << " " << e[i].w << endl;
        }
    }
    // yout << T << ' ' << dis[T] << endl;
    return dis[T] > -inf;
}
long long sum, ans;
int check()
{
    long long fl = inf, delta;
    for (int i = frm[T]; i; i = frm[e[i].u])
        fl = min(fl, e[i].w);
    delta = dis[T] * fl;
    if (sum + delta < 0)
    {
        ans += sum / (-dis[T]);
        return 0;
    }
    else
    {
        sum += delta;
        ans += fl;
        for (int i = frm[T]; i; i = frm[e[i].u])
            e[i].w -= fl, e[i ^ 1].w += fl;
        return 1;
    }
}
signed main()
{
    yin >> n;
    for (int i = 1; i <= n; i++)
        yin >> a[i];
    for (int i = 1; i <= n; i++)
        yin >> b[i];
    for (int i = 1; i <= n; i++)
        yin >> c[i];
    S = 0, T = n + 1;
    for (int i = 1; i <= n; i++)
        cnt[i] = prime(a[i]);
    for (int i = 1; i <= n; i++)
    {
        if (cnt[i] & 1)
            add(S, i, b[i], 0);
        else
            add(i, T, b[i], 0);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!(cnt[i] & 1))
            continue;
        for (int j = 1; j <= n; j++)
        {
            if (cnt[i] == cnt[j] + 1 && a[i] % a[j] == 0)
                add(i, j, inf, 1ll * c[i] * c[j]);
            if (cnt[i] == cnt[j] - 1 && a[j] % a[i] == 0)
                add(i, j, inf, 1ll * c[i] * c[j]);
        }
    }
    // puts("!!!");
    while (bfs() && check())
        ;
    yout << ans << endl;
    return 0;
}