黑妹的游戏IV

题目链接:https://www.nowcoder.com/acm/contest/130/D


解题思路:网络流,预处理出所有的(i,j)对和(p,q)对,源点S和(i,j)连容量为1的边,(p,q)和汇点T连容量为1的边,如果(i,j)和(p,q)可以同时选择则连容量为1的边。跑一遍最大流即可得出答案。

边数可能很大,注意到(i,j)和(p,q)可以连边的条件是不互质,可以将质因子作为中间点,(i,j)如果有质因子v,则(i,j)向v连一条容量为INF的边,(p,q)同理。


#include <iostream>   
#include <cstdio>   
#include <cstring>   
#include <string>   
#include <algorithm>   
#include <cmath>  
#include <map>   
#include <set>  
#include <stack>  
#include <queue>   
#include <vector>   
#include <bitset>   
#include <functional>   

using namespace std;

#define LL long long  
const int INF = 0x3f3f3f3f;

int n, cnt;
int a[409], b[409];
int prime[400009], tot, vis[400009];
map<int, int>in, out;

struct node
{
	int u, v, next, cap;
} edge[4009 * 10 * 409];
int s[160009], d[160009], visit[160009];

int gcd(int x, int y) {
	return x ? gcd(y % x, x) : y;
}

void init() {
	cnt = 0;
	memset(s, -1, sizeof s);
	tot = 0;
	vis[0] = vis[1] = 1;
	for (int i = 2; 1LL * i * i < 1e9; i++) {
		if (!vis[i]) {
			prime[tot++] = i;
			for (int j = 2 * i; 1LL * j * j <= 1e9; j += i) vis[j] = 1;
		}
	}
}

void add(int u, int v, int c)
{
	edge[cnt].u = u;
	edge[cnt].v = v;
	edge[cnt].cap = c;
	edge[cnt].next = s[u];
	s[u] = cnt++;
	edge[cnt].u = v;
	edge[cnt].v = u;
	edge[cnt].cap = 0;
	edge[cnt].next = s[v];
	s[v] = cnt++;
}

bool BFS(int ss, int ee)
{
	memset(d, 0, sizeof d);
	d[ss] = 1;
	queue<int>q;
	q.push(ss);
	while (!q.empty())
	{
		int pre = q.front();
		q.pop();
		for (int i = s[pre]; ~i; i = edge[i].next)
		{
			int v = edge[i].v;
			if (edge[i].cap > 0 && !d[v])
			{
				d[v] = d[pre] + 1;
				q.push(v);
			}
		}
	}
	return d[ee];
}

int DFS(int x, int exp, int ee)
{
	if (x == ee || !exp) return exp;
	int temp, flow = 0;
	for (int i = s[x]; ~i; i = edge[i].next)
	{
		int v = edge[i].v;
		if (d[v] == d[x] + 1 && (temp = (DFS(v, min(exp, edge[i].cap), ee))) > 0)
		{
			edge[i].cap -= temp;
			edge[i ^ 1].cap += temp;
			flow += temp;
			exp -= temp;
			if (!exp) break;
		}
	}
	if (!flow) d[x] = 0;
	return flow;
}

int Dinic_flow(int ss, int ee)
{
	int ans = 0;
	while (BFS(ss, ee))
	{
		ans += DFS(ss, INF, ee);
	}
	return ans;
}


int main()
{
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
		for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
		init();
		in.clear();
		out.clear();
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				int tmp = gcd(a[i], b[j]);
				if (tmp == 1) continue;
				if (a[i] < b[j]) in[tmp]++;
				if (a[i] > b[j]) out[tmp]++;
			}
		}
		int insum = in.size();
		int outsum = out.size();
		int p = 1;
		for (map<int, int>::iterator it = in.begin(); it != in.end(); it++, p++) {
			int tmp = it->first;
			add(0, p + 1, it->second);
			for (int k = 0; k < tot && prime[k] <= tmp; k++) {
				if (tmp % prime[k] == 0) {
					add(p + 1, insum + outsum + k + 2, INF);
					while (tmp % prime[k] == 0) tmp /= prime[k];
				}
			}
			if (tmp != 1) {
				prime[tot++] = tmp;
				add(p + 1, insum + outsum + tot + 1, INF);
			}
		}
		p = 1;
		for (map<int, int>::iterator it = out.begin(); it != out.end(); it++, p++) {
			int tmp = it->first;
			add(p + 1 + insum, 1, it->second);
			for (int k = 0; k < tot && prime[k] <= tmp; k++) {
				if (tmp % prime[k] == 0) {
					add(insum + outsum + 2 + k, p + 1 + insum, INF);
					while (tmp % prime[k] == 0) tmp /= prime[k];
				}
			}
			if (tmp != 1) {
				prime[tot++] = tmp;
				add(insum + outsum + 1 + tot, p + 1 + insum, INF);
			}
		}
		printf("%d\n", Dinic_flow(0, 1));
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值