【LOJ】#2031. 「SDOI2016」数字配对

题解

这个图是个二分图,因为如果有一个奇环的话,我们会发现一个数变成另一个数要乘上个数不同的质数,显然不可能

然后我们发现这个不是求最大流,而是问一定价值的情况下最大流是多少,二分一个流量,加上一条边限流,然后求最小费用(其实是最大费用,把权值取反即可)是不是小于等于0,再看流量有没有流满

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
//#define ivorysi
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define mo 974711
#define MAXN 15005
#define RG register
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
	    while(c < '0' || c > '9') {
			if(c == '-') f = -1;
			c = getchar();
	    }
	    while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {putchar('-');x = -x;}
    if(x >= 10) {
		out(x / 10);
    }
    putchar('0' + x % 10);
}
int N;
int a[405],b[405],col[405];
int64 c[405],g[405][405];
bool vis[405],E[405][405];
int totflow;
int64 totval,pi1;
struct node {
	int to,next,cap;
	int64 val;
}Edge[500005];
int head[407],sumE,S,T;
void add(int u,int v,int c,int64 a) {
	Edge[++sumE].to = v;Edge[sumE].next = head[u];
	Edge[sumE].cap = c;Edge[sumE].val = a;
	head[u] = sumE;
}
void addtwo(int u,int v,int c,int64 a) {
	add(u,v,c,a);add(v,u,0,-a);
}
bool check(int x) {
	if(x == 1) return false;
	for(int i = 2 ; i <= x / i ; ++i) {
		if(x % i == 0) return false;
	}
	return true;
}
void dfs(int u,int id) {
	vis[u] = 1;
	col[u] = id;
	for(int v = 1 ; v <= N ; ++v) {
		int s = a[u],t = a[v];
		if(s < t) swap(s,t);
		if(s % t == 0 && check(s / t)) {
			g[u][v] = g[v][u] = -c[u] * c[v];
			E[u][v] = E[v][u] = 1;
			if(!vis[v]) dfs(v,id ^ 1);
		}
	}
}
int aug(int u,int C) {
	if(u == T) {
		totflow += C;
		totval += pi1 * C;
		return C;
	}
	int flow = 0;
	vis[u] = 1;
	for(int i = head[u] ; i ; i = Edge[i].next) {
		int v = Edge[i].to;
		if(Edge[i].cap && !vis[v] && Edge[i].val == 0) {
			int t = aug(v,min(C - flow,Edge[i].cap));
			flow += t;
			Edge[i].cap -= t;
			Edge[i ^ 1].cap += t;
			if(flow == C) return flow;
		}
	}
	return flow;
}
bool modlabel() {
	int64 d = 1e18;
	for(int i = 1 ; i <= T ; ++i) {
		if(vis[i]) {
			for(int j = head[i] ; j ; j = Edge[j].next) {
				int v = Edge[j].to;
				if(Edge[j].cap && !vis[v] && Edge[j].val < d) 
					d = Edge[j].val;
			}
		}
	}
	if(d == 1e18) return false;
	pi1 += d;
	for(int i = 1 ; i <= T ; ++i) {
		if(vis[i]) {
			for(int j = head[i] ; j ; j = Edge[j].next) {
				Edge[j].val -= d;
				Edge[j ^ 1].val += d;
			}
		}
	}
	return true;
}
bool check_flow(int MID) {
	memset(head,0,sizeof(head));sumE = 1;
	totval = 0;totflow = 0;pi1 = 0;
	for(int i = 1 ; i <= N ; ++i) {
		if(!col[i]) addtwo(N + 1,i,b[i],0);
		else addtwo(i,T,b[i],0);
	}
	for(int i = 1 ; i <= N ; ++i) {
		if(!col[i]) {
			for(int j = 1 ; j <= N ; ++j) {
				if(col[j] && E[i][j]) {
					addtwo(i,j,0x7fffffff,g[i][j]);
				} 
			}
		}
	}
	addtwo(S,N + 1,MID,0);
	do {
		do{
			memset(vis,0,sizeof(vis));
		}while(aug(S,0x7fffffff));
	}while(modlabel());
	return totflow >= MID && totval <= 0;
}
void Init() {
	read(N);
	for(int i = 1 ; i <= N ; ++i) read(a[i]);
	for(int i = 1 ; i <= N ; ++i) read(b[i]);
	for(int i = 1 ; i <= N ; ++i) read(c[i]);
	for(int i = 1 ; i <= N ; ++i)
		if(!vis[i]) dfs(i,0);
	S = N + 2;T = N + 3;
}
void Solve() {
	int L = 0,R = 0;
	for(int i = 1 ; i <= N ; ++i) R += b[i];
	R /= 2;
	while(L < R) {
		int mid = (L + R + 1) >> 1;
		if(check_flow(mid)) L = mid;
		else R = mid - 1;
	}
	out(L);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
    return 0;
}
posted @ 2018-06-01 10:05  sigongzi  阅读(362)  评论(2编辑  收藏  举报