思路 首先想到費用流。 對於每個點拆點。然後考慮我們怎樣才能保證每個點只被用一次。 如果$i$與$j$滿足條件。那麼就從$i$向$j$連一條邊並且從$j$向$i$連一條 ...
思路
首先想到費用流。
對於每個點拆點。然後考慮我們怎樣才能保證每個點只被用一次。
如果\(i\)與\(j\)滿足條件。那麼就從\(i\)向\(j\)連一條邊並且從\(j\)向\(i\)連一條邊。這樣每次增廣的時候我們都可以看作某一條邊被增廣了兩次。顯然從\(i\)到\(j\)和從\(j\)到\(i\)的邊是等價的。也就是說,如果當前增廣這兩個點之間的邊更優秀,那麼在增廣完成從\(i\)到\(j\)和從\(j\)到\(i\)這兩條邊流量變為\(0\)之前不回去增廣其他的邊。
比較難解釋,仔細想一下可以發現是對的。這樣最後我們找出的流量實際上是答案的兩倍。除二即可。
然後還要考慮題目中對於價值的限制。我們把價值當作費用,每次增廣費用最大的路徑。直到如果再增廣費用變為負數為止。
代碼
/*
* @Author: wxyww
* @Date: 2019-02-17 14:52:25
* @Last Modified time: 2019-02-17 19:36:45
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 410,M = 1000000 + 100,INF = 1e9;
ll read() {
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
struct node {
int v,nxt,w;
ll cost;
}e[M];
int head[N],ejs = 1;
void add(int u,int v,int w,ll c) {
e[++ejs].v = v;e[ejs].w = w;e[ejs].cost = c;e[ejs].nxt = head[u];head[u] = ejs;
e[++ejs].v = u;e[ejs].w = 0;e[ejs].cost = -c;e[ejs].nxt = head[v];head[v] = ejs;
}
int a[N],vis[N],fa[N],b[N];
ll dis[N],c[N];
queue<int>q;
int S,T;
bool pd(int x,int y) {
if(x < y) swap(x,y);
if(!y || x == y) return false;
if(x % y) return false;
int k = x/y;
for(int i = 2;i * i <= k;++i)
if(k % i == 0) return false;
return true;
}
bool spfa() {
while(!q.empty()) q.pop();
memset(dis,-0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(fa,0,sizeof(fa));
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(dis[v] < dis[u] + e[i].cost && e[i].w) {
dis[v] = dis[u] + e[i].cost;
fa[v] = i;
if(!vis[v]) q.push(v),vis[v] = 1;
}
}
}
return fa[T];
}
ll dinic() {
ll COST = 0,FLOW = 0;
while(spfa()) {
int mn = INF;
for(int i = fa[T];i;i = fa[e[i ^ 1].v]) mn = min(mn,e[i].w);
for(int i = fa[T];i;i = fa[e[i ^ 1].v]) e[i].w -= mn,e[i ^ 1].w += mn;
if(COST + dis[T] * mn < 0) {
FLOW += COST / -dis[T];
return FLOW;
}
COST += dis[T] * mn;
FLOW += mn;
}
return FLOW;
}
int main() {
int n = read();
for(int i = 1;i <= n;++i) a[i] = read();
for(int i = 1;i <= n;++i) b[i] = read();
for(int i = 1;i <= n;++i) c[i] = read();
S = n * 2 + 1,T = S + 1;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= n;++j)
if(i != j && pd(a[j],a[i]))
add(i,j + n,INF,c[i] * c[j]);
int tot = ejs;
for(int i = 1;i <= n;++i) add(S,i,b[i],0);
for(int i = 1;i <= n;++i) add(i + n,T,b[i],0);
cout<<(dinic() >> 1);
return 0;
}