P4068 [SDOI2016]数字配对

 https://www.luogu.com.cn/problem/P4068

质因数分解然后建立二分图,跑费用流

具体看第一个官方题解的代码就好了,我想说的是费用流控制流量使得费用大于0且流量最大的方法,具体看代码,受益匪浅

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
typedef long long ll;

const ll inf = 1e16;
const int maxn = 1005;
const int M = 1005;

queue<int> que;
int head[maxn];
struct Edge{
	int id,nex;
	ll w,f;
}edge[M<<1];

int cnt = 0;

void init(){
	cnt=0;
	memset(head,-1,sizeof(head));
	while(que.size()) que.pop();
	
}

void add_(int x,int y,ll f,ll w){
	edge[cnt].id = y;
	edge[cnt].f = f;
	edge[cnt].w = w;
	edge[cnt].nex = head[x];
	head[x] = cnt ++ ;
}

void add(int x,int y,ll f,ll w){
	add_(x,y,f,w);
	add_(y,x,0,-w);
}

int n,m;


int vis[maxn];
ll dis[maxn];
ll mflow[maxn];
int per[maxn];



int spfa(int s,int t){
	for (int i = 0; i<= n+16 ; i++ ){
		vis[i] = 0;
		dis[i] = inf;
	}
	
	 
	mflow[s] = inf;
	que.push(s);
	dis[s] = 0;
	vis[s] = 1;
	
	while(que.size()){
		int x=  que.front();
		que.pop();
		vis[x] = 0;
		for (int i = head[x]; ~i; i = edge[i].nex){
			int v = edge[i].id;
			if(dis[v] > dis[x] + edge[i].w && edge[i].f){
				dis[v] = dis[x] + edge[i].w;
				per[v] = i;
				mflow[v] = min(mflow[x],edge[i].f);
				if(vis[v])	continue;
				
				vis[v] = 1;
				que.push(v);
			}
		}
	}
	if(dis[t] != inf)	return 1;
	else return 0;
}
///!!!!!!!

void update(int s,int t, ll& flow){
	ll minn = mflow[t];
	for (int i = t; i != s; i = edge[per[i] ^ 1].id){//沿着路走 
		
		int x = per[i];
		edge[x].f -= minn;
		edge[x^1].f += minn;
	}
	flow += minn;
}
int len = 0;
ll solve(int s,int t, ll& flow){
	ll ans = 0;
	len = 0;
	while(spfa(s,t)){//鐢╯pfa寮€璺?
		if(ans + dis[t] * mflow[t] > 0){
			
			flow -= ans/dis[t]; 
			return ans;
		}
		ans += dis[t] * mflow[t];
		update(s,t,flow);
	}
	return ans;
}
//----------------------------------------------------------------------------------------
//以上是网络流模板
const int Maxn = 1e5+7;
int prime[Maxn];
int Mark[Maxn+1];
 
int sieve() {
 
    int p = 0;
 
    Mark[0] = 1; Mark[1] = 1;
    for (int i = 2; i < Maxn; i++){
        if (Mark[i] == 0) {
            prime[p++] = i;
        }
        for (int j = 0; j < p && prime[j] * i < Maxn; j++){
            Mark[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                break;
            }
        }
    }
    return p;
}

int chal;
 
ll a[maxn],b[maxn],c[maxn];
int ans[maxn];

int cal(int x){
	int cns = 0;
	for(int i = 2;1LL*i*i<= x;i++){
		while(x % i == 0){
			x /= i;
			cns++;
		}
	}
	if(x > 1 ) cns ++;
	return cns;
}



int main(){ 

	init();
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%lld",&b[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%lld",&c[i]);
	}
	for(int i=1;i<=n;i++){
		ans[i] = cal(a[i]);//有几个质数因子 
	}
	
	for(int i=1;i<=n;i++){
		if(ans[i] & 1 ){
			
			for(int j=1;j<=n;j++){
				if(ans[j] %2 == 0 ){
					if(a[i] % a[j] == 0 && ans[j] + 1 == ans[i]){
						add(i,j,inf,-1LL*c[i]*c[j]);
					}
					else if(a[j] % a[i] == 0 && ans[i] + 1== ans[j] ){
						add(i,j,inf,-1LL*c[i]*c[j]);
					}
				}
			}	
		}
	}
	int s,t;
	
	s = 0;
	t = n+11;
	for(int i=1;i<=n;i++){
		if(ans[i] & 1){
			add(s,i,b[i],0);
//			cout<<s<<" "<<i<<" "<<b[i]<<endl;
		}
		else{
			add(i,t,b[i],0);
//			cout<<i<<" "<<t<<" "<<b[i]<<endl;
		}
	}
	ll f = 0;
	ll cc = solve(s,t,f);
	printf("%lld
",f);
}
/*

3
2 4 8
2 200 7
-1 -2 1
4


*/

  

寻找真正的热爱
原文地址:https://www.cnblogs.com/lesning/p/13710546.html