• [SDOI2016]数字配对


    题解

    一道有意思的网络流
    首先一眼匹配类问题数据范围不大就想到网络流
    但是发现了一个问题
    一个数字只能参与一次匹配
    所以继续从原题中发现条件
    如果(ai/aj)是质数才会连边
    那么我们就可以考虑对每个数质因数分解
    (t[i])表示(i)的每个质因子的幂的和
    那么可以发现能连边的点((i,j))一定满足(|t[i]-t[j]|=1且a[i]|a[j]或a[j]|a[i])
    那么这么一来就可以看出来是二分图了
    (S->t[i]%2=1 \t[i]%2=0->T)
    然后再把可以配对的点连上
    直接最大费用最大流跑就行了
    然后题目还有一个限制条件:要满足价值不小于0
    所以我们就在每次找到一条增广路的时候看流完这条增广路会不会使价值小于0
    如果小于0则找一个使价值不小于0的流量流完这条增广路然后退出

    代码

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    # define LL long long
    const int M = 255 ;
    const int N = 100005 ;
    const int INF = 1e8 ;
    using namespace std ;
    
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    
    queue < int > q ;
    bool vis[M] , notp[N] ;
    int pnum , pri[N] ;
    int n , a[M] , b[M] , c[M] , t[M] ;
    int S , T , num = 1 , hea[M] , cnt , pre[M] ;
    LL dis[M] , mc , mf , ans ;
    struct E { int nxt , to ; LL dis , cst ; } edge[N] ;
    inline void add_edge(int from , int to , LL dis , LL cst) {
        edge[++num].nxt = hea[from] ; edge[num].to = to ;
        edge[num].dis = dis ; edge[num].cst = cst ; hea[from] = num ;
    }
    inline void Insert(int u , int v , LL w , LL c) {
        add_edge(u , v , w , -c) ;
        add_edge(v , u , 0 , c) ;
    }
    inline int Calc(int n) {
        int ret = 0 ;
        for(int i = 1 ; n > 1 && 1LL * pri[i] * pri[i] <= n ; i ++)
            while(n % pri[i] == 0) n /= pri[i] , ++ ret ;
        if(n > 1) ++ ret ;
        return ret ;
    }
    inline void presolve(int n) {
    	for(int i = 2 ; i <= n ; i ++) {
    		if(!notp[i]) pri[++pnum] = i ;
    		for(int j = 1 ; j <= pnum && 1LL * i * pri[j] <= n ; j ++) {
    			notp[i * pri[j]] = true ;
    			if(i % pri[j] == 0) break ;
    		}
    	}
    }
    inline bool spfa() {
        queue < int > q ; q.push(S) ; pre[T] = -1 ;
        memset(dis , 63 , sizeof(dis)) ; dis[S] = 0 ;
        while(!q.empty()) {
            int u = q.front() ; q.pop() ; vis[u] = false ;
            for(int i = hea[u] ; i ; i = edge[i].nxt) {
                int v = edge[i].to ;
                if(dis[v] > dis[u] + edge[i].cst && edge[i].dis > 0) {
                    dis[v] = dis[u] + edge[i].cst ; 
                    pre[v] = i ; if(vis[v]) continue ;
                    vis[v] = true ; q.push(v) ;
                }
            }
        }
        return (pre[T] > 0) ;
    }
    inline void Solve() {
    	LL diss ;
        while(spfa()) {
            diss = INF ;
            for(int i = T ; i != S ; i = edge[pre[i] ^ 1].to) diss = min(diss , edge[pre[i]].dis) ;
    		for(int i = T ; i != S ; i = edge[pre[i] ^ 1].to) edge[pre[i]].dis -= diss , edge[pre[i] ^ 1].dis += diss ;
      		if(mc - dis[T] * diss < 0) {
      			ans += min(diss , mc / dis[T]) ;
      			break ;
    		}
            mf += diss ; mc -= dis[T] * diss ;
        }
        ans += mf ;
    }
    
    int main() {
    	presolve(100000) ;
        n = read() ; S = 0 , T = n + 1 ;
        for(int i = 1 ; i <= n ; i ++) a[i] = read() ;
        for(int i = 1 ; i <= n ; i ++) t[i] = Calc(a[i]) ;
        for(int i = 1 ; i <= n ; i ++) {
    		b[i] = read() ;
    		if(t[i] % 2) Insert(S , i , b[i] , 0) ;
    		else Insert(i , T , b[i] , 0) ;
    	}
        for(int i = 1 ; i <= n ; i ++) c[i] = read() ;
        for(int i = 1 ; i <= n ; i ++) {
        	if(t[i] % 2 == 0) continue ;
        	for(int j = 1 ; j <= n ; j ++) {
        		if(t[j] % 2 == 0 && abs(t[j] - t[i]) == 1 && (a[i] % a[j] == 0 || a[j] % a[i] == 0))
    				Insert(i , j , INF , 1LL * c[i] * c[j]) ; 
    		}
    	}
        Solve() ;
        printf("%lld
    ",ans) ;
        return 0 ;
    }
    
  • 相关阅读:
    软件工程作业-结对实验
    软件工程实践作业2
    UNIX线程之间的关系
    c中计时的几种方法
    调试器工作原理(3):调试信息
    调试器工作原理(2):实现断点
    调试器工作原理(1):基础篇
    linux的终端,网络虚拟终端,伪终端(转)
    asterisk webrtc使用SIPML5初体验
    初次使用nodejs的问题
  • 原文地址:https://www.cnblogs.com/beretty/p/10459011.html
Copyright © 2020-2023  润新知