zoukankan      html  css  js  c++  java
  • [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 ;
    }
    
  • 相关阅读:
    QuantLib 金融计算
    【翻译】《理解收益率曲线》系列
    QuantLib 金融计算——C++ 代码改写成 Python 程序的一些经验
    可转债研报阅读笔记
    SWIG 3 中文手册——13. 约定
    SWIG 3 中文手册——12. 自定义功能
    SWIG 3 中文手册——11. 类型映射
    【翻译】Quant 应该怎样写博客?
    QuantLib 金融计算——案例之普通利率互换分析(2)
    仿射期限结构模型:理论与实现——实现部分
  • 原文地址:https://www.cnblogs.com/beretty/p/10459011.html
Copyright © 2011-2022 走看看