\(Solution\)
考虑\(a_i\)的限制,设\(a_i = \prod {p_i^{k_i}},s_i = \sum{k_i}\)
对于条件,当且仅当\(a_j | a_i\)且\(s_i = s_j + 1\),以\(s_i\)的奇偶分为两个集合,发现是一个二分图,\(b_i\)则为流量,而对于权值大于\(0\)的限制,做完单源增广路后,改变流量即可。
\(Code\)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int inf = 2147483647;
int n,S,T,a[205],b[205],h[205],p[100005],vis[100005],cnt,tot = 1,pre[205];
int viss[205],up[205],flow[205],q[2000005],s[205];
LL dis[205],c[205];
struct edge{
int to,nxt,flw;
LL v;
}e[1000005];
void add(int x,int y,int z,LL z2)
{
e[++tot] = edge{y,h[x],z,z2},h[x] = tot;
e[++tot] = edge{x,h[y],0,-z2},h[y] = tot;
}
void init()
{
for (int i = 2; i <= 100000; i++)
{
if (!vis[i]) p[++cnt] = i;
for (int j = 1; j <= cnt && i * p[j] <= 100000; j++)
{
vis[p[j] * i] = 1;
if (i % p[j] == 0) break;
}
}
}
int spfa()
{
for (int i = 0; i <= 204; i++) dis[i] = -1e18;
memset(viss,0,sizeof vis);
memset(flow,127,sizeof flow);
int head = 0,tail = 1;
q[1] = S,dis[S] = 0,vis[S] = 1,pre[T] = -1;
while (head < tail)
{
int u = q[++head]; viss[u] = 0;
for (int i = h[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (dis[v] < dis[u] + e[i].v && e[i].flw > 0)
{
dis[v] = dis[u] + e[i].v,pre[v] = u,up[v] = i;
flow[v] = min(flow[u],e[i].flw);
if (!viss[v]) viss[v] = 1,q[++tail] = v;
}
}
}
return (pre[T] == -1 ? 0 : 1);
}
int main()
{
init();
scanf("%d",&n),S = n + 1,T = S + 1;
for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
for (int i = 1; i <= n; i++) scanf("%d",&b[i]);
for (int i = 1; i <= n; i++) scanf("%lld",&c[i]);
for (int i = 1; i <= n; i++)
{
int g = a[i];
for (int j = 1; j <= cnt && g > 1; j++)
while (g % p[j] == 0) g /= p[j],s[i]++;
if (g > 1) s[i]++;
if (s[i] & 1) add(S,i,b[i],0);
else add(i,T,b[i],0);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (a[i] % a[j] == 0 && i != j && s[i] == s[j] + 1)
{
if (s[i] & 1) add(i,j,inf,c[i] * c[j]);
else add(j,i,inf,c[i] * c[j]);
}
int al = 0; LL av = 0;
while (spfa())
{
int o = T,F,k;
if (dis[T] == 0) k = 0;
else k = av / dis[T];
if (dis[T] >= 0) F = flow[T];
else F = min(flow[T],abs(k));
if (F == 0) break;
al += F,av += (LL)dis[T] * F;
for (; o != S; o = pre[o]) e[up[o]].flw -= F,e[up[o] ^ 1].flw += F;
}
printf("%d\n",al);
}