zoukankan      html  css  js  c++  java
  • CF1430G

    CF1430G [* easy]

    给定一张 DAG,你需要给每个点分配点权 (a),使得对于一条有向边,(u o v,w),有 ((a_u-a_v)>0)

    最小化 (sum w_i imes (a_u-a_v))

    (nle 18,mle frac{n(n-1)}{2})

    Solution

    考虑 (f_x=sum_{x o v}w_i-sum_{v o x}w_i)

    答案即为 (sum a_i imes f_i)

    限制等价于 DAG 上每个点的点权大于其出边的点权。

    考虑按照点权进行分层,第 (i) 层的点权为 (i),那么对答案的贡献即为 (sum i imes sum_{S})

    这样太诡异了,考虑差分,变成 (sum sum_{T-S})(T) 表示全集。

    然后就可以类似于宝藏,枚举子集转移了,转移的前提是这个子集本身合法(内部无边)同时转移到的 (ioplus S) 满足不存在到 (S) 的边,也预处理一下即可。

    复杂度 (mathcal O(3^n)),CF 少爷机,貌似可以过。

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define re register
    #define pb push_back
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int N = 20 ; 
    const int inf = 1e16 + 7 ; 
    int n, m, cnt, f[N], a[N][N], b[N], w[N], g[1 << 18], bit[1 << 18] ;
    long long dp[1 << 18], fr[1 << 18], sum[1 << 18] ; 
    bool vis[1 << 18] ; 
    vector<int> G[N] ;
    void print(int S) {
    	if( S == 0 ) return ; 
    	print(fr[S]) ;
    	++ cnt ; int u = (S ^ fr[S]) ;
    	rep( j, 1, n ) {
    		if((1 << (j - 1)) & u) b[j] = cnt ; 
    	}
    }
    signed main()
    {
    	n = gi(), m = gi() ; int x, y, z ; 
    	rep( i, 1, m ) {
    		x = gi(), y = gi(), z = gi() ; 
    		a[x][y] = 1, f[x] += z, f[y] -= z ; 
    		G[x].pb(y) ; 
    	}
    	int lim = (1 << n) - 1 ; 
    	rep( i, 0, lim ) {
    		rep( j, 1, n ) if( (1 << (j - 1)) & i ) sum[i] += f[j], ++ bit[i] ;  
    		rep( j, 1, n ) if( (1 << (j - 1)) & i ) w[j] = 1 ; 
    		rep( j, 1, n ) if( (1 << (j - 1)) & i ) {
    			for(int v : G[j]) if( w[v] ) vis[i] = 1 ;
    			for(int v : G[j]) g[i] |= (1 << (v - 1)) ; 
    		}
    		rep( j, 1, n ) w[j] = 0 ; 
    	}
    	memset( dp, 63, sizeof(dp) ) ;
    	dp[0] = 0 ;
    	rep( S, 1, lim ) {
    		for(re int i = S; ; i = (i - 1) & S ) {
    			if( vis[i ^ S] || (g[i] & (i ^ S)) ) {
    				if( i == 0 ) break ; 
    				continue ; 
    			}
    			if( i == S ) continue ; 
    			if( dp[S] > dp[i] + sum[lim ^ i] ) {
    				dp[S] = dp[i] + sum[lim ^ i] ;
    				fr[S] = i ; 
    			}
    			if( i == 0 ) break ; 
    			continue ; 
    		}
    	}
    	print(lim) ; 
    	rep( j, 1, n ) printf("%d ", b[j] ) ;  
    	return 0 ;
    }
    
  • 相关阅读:
    开源魔兽世界私服搭建
    centos7 普通用户无法使用ssh登录其他服务器
    Java时间格式大全
    C#中的线程之Abort陷阱
    C# 多线程学习系列四之ThreadPool取消、超时子线程操作以及ManualResetEvent和AutoResetEvent信号量的使用
    C# ThreadPool类(线程池)
    VS2019输出信息到调试控制台
    Stream/Bytes[]/Image对象相互转化
    Asp.NetCore 读取配置文件帮助类
    Java SpringBoot使用126邮箱发送html内容邮件,带附件
  • 原文地址:https://www.cnblogs.com/Soulist/p/13804519.html
Copyright © 2011-2022 走看看