• 【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('
    ')
    #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;
    }
    
  • 相关阅读:
    Java Web----Java Web的数据库操作(二)
    PHP foreach 遍历数组是打印出相同的数据
    implemented loader.php
    With PHP frameworks, why is the “route” concept used?
    网络包
    长寿之道
    php中print_r 和var_dump 打印变量的区别。
    php 中的全局变量的理解
    php session 严格过期时间实现
    nginx+fastcgi php 使用file_get_contents、curl、fopen读取localhost本站点.php异常的情况
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9120327.html
Copyright © 2020-2023  润新知