P4068 [SDOI2016]数字配对

增广时费用为负停掉即可 注意开long long

#include <bits/stdc++.h>
using namespace std;
//using ll = long long;

#define int long long
const int V = 201000;
const int E = 2010000;

template<typename T>
struct MinCostGraph {
	int s, t, vtot;
	int h[V], idx;
	T d[V], flow, cost;
	int pre[V];
	bool vis[V];
	int f[E * 2];
	int w[E * 2];
	int e[E * 2];
	int ne[E * 2];
	void add(int a, int b, int c, int d) {
		e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx ++ ;
		e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx ++ ;
	}

	bool spfa() {
		T inf = numeric_limits<T>::max() / 2;
		for (int i = 1; i <= vtot; i++) {
			d[i] =  inf;
			vis[i] = false;
			pre[i] = -1;
		}
		d[s] = 0;
		vis[s] = true;
		queue<int> q;
		q.push(s);
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			vis[u] = false;
			for(int i = h[u]; ~i; i = ne[i]) {
				int v = e[i];
				if (f[i] && d[v] > d[u] + w[i]) {
					d[v] = d[u] + w[i];
					pre[v] = i;
					if (!vis[v]) {
						vis[v] = 1;
						q.push(v);
					}
				}
			}
		}
		return d[t] != inf;
	}
	int  fl = 0;
	void augment() {
		int u = t;
		T q = numeric_limits<T>::max();
		while (~pre[u]) {
			q = min(q, 1ll * f[pre[u]]);
			u = e[pre[u] ^ 1];
		}
		int tot = cost;
		int www = flow;
		//flow += q;
		if(tot + q * d[t] > 0) {
			flow +=  -tot / (d[t]);
			fl = 1;
			return ;
		}
		flow += q;
		cost += q * d[t];
		u = t;
		while (~pre[u]) {
			f[pre[u]] -= q;
			f[pre[u] ^ 1] += q;
			u = e[pre[u] ^ 1];
		}
	}

	pair<T, T> solve() {
		flow = 0;
		cost = 0;
		while (spfa() && !fl) augment();
		return {flow, cost};
	}
	void init(int s_, int t_, int vtot_) {
		s = s_;
		t = t_;
		vtot = vtot_;
		idx = 0;
		for (int i = 1; i <= vtot; i++) h[i] = -1;
	}
};

MinCostGraph<int> g;
int n, m;
int S, T;
const int N = 2e5 + 10;
int cnt[N];
int idx , p[N], v[N];
void init(int n ) {
	for(int i = 2; i <= n; i++) {
		if(!v[i])p[++idx] = i;
		for(int j = 1; j <= idx && i * p[j] <= n; j++) {
			v[i * p[j]] = 1;
			if(i % p[j] == 0)break;
		}
	}
}
int work(int n) {
	int t = 0;
	for(int i = 1; p[i]*p[i] <= n; i++) {
		if(n % p[i] == 0) {
			while(n % p[i] == 0) n /= p[i], t++;
		}
	}
	if(n > 1)t++;
	return t;
}
int a[N], b[N], c[N];
signed main() {

	init(N - 10);
	cin >> n;
	S = n + 1;
	T = n + 2;
	g.init(S, T, T);
	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++)cnt[i] = work(a[i]);
	//for(int i = 1; i <= n; i++)cout << cnt[i] << " \n"[i == n];
	for(int i = 1; i <= n; i++) if(cnt[i] & 1) g.add(S, i, b[i], 0);
		else  g.add(i, T, b[i], 0);
	for(int i = 1; i <= n; i++) if(cnt[i] & 1) {
			for(int j = 1; j <= n; j++) {
				if(cnt[j] & 1)continue;
				if((cnt[i] + 1 == cnt[j] && a[j] % a[i] == 0) || (cnt[j] + 1 == cnt[i] && a[i] % a[j] == 0)) {
					g.add(i, j, 1ll << 60,  -1ll * c[i]*c[j]);
				}
			}
		}
	pair<int, int>t;
	t = g.solve();
	cout << t.first << endl;

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值