zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 152

    AtCoder Beginner Contest 152 - F - Tree and Constraints (容斥定理+树上路径的性质)

    We have a tree with NN vertices numbered 11 to NN. The ii-th edge in this tree connects Vertex aiai and Vertex bibi.
    Consider painting each of these edges white or black. There are 2N−12N−1 such ways to paint the edges. Among them, how many satisfy all of the following MM restrictions?

    • The ii-th (1≤i≤M)(1≤i≤M) restriction is represented by two integers uiui and vivi, which mean that the path connecting Vertex uiui and Vertex vivi must contain at least one edge painted black.

    题意:

    给定一个含有n个节点的树,每一条边可以给其染成黑色或者白色。

    还有m个限制条件,每一个限制条件包括两个节点(u,v),限制为(u,v)节点之间的路径中必须包含至少一个涂成黑色的边。

    问有多少种染色方法使其同时满足m个条件。

    思路:

    答案(ans=v1-v2)

    (v1)代表所有染色方案,(v2)代表不满足条件的染色方案

    我们知道(v1=2^{n-1})

    那么问题就直接转换成了求(v2)

    (A_i)代表不满足第i个限制条件的方案数,那么(v2)就等于(A_i)的并集,即(v2=igcup_1^{m} A_i)

    根据容斥定理:

    img那么我们就可以直接枚举(m)个限制的所有集合来求出(v2)

    那么问题来了,怎么求(A_i)呢?

    (path_j)代表从根节点(无根树的话就假定一个根)到第(j)个节点经过了哪些边。

    因为(nleq 50),所以(path_i)我们采用$long long $ 数据类型进行二进制状态压缩表示。

    那么节点(x,y)之间的路径经历的边信息(info=path_x oplus path_y)(oplus) 是抑或符号。

    那么对于枚举的每一个集合(i),把包含的所有限制的边信息(info)或起来后计算有多少个边,假设个数为(num)

    那么这(num)个边染成白色时集合(i)才不满足条件。那么剩下(free=n-1-num)个边可以自由染色。

    直接根据奇偶判断在容斥定理中公式的正负号即可。

    代码:

    int n;
    int m;
    std::vector<int> v[maxn];
    ll path[maxn];
    void dfs(int x, int pre, ll num)
    {
    	path[x] = num;
    	for (auto y : v[x])
    	{
    		if (y == pre)
    		{
    			continue;
    		}
    		dfs(y, x, num | (1ll << y));
    	}
    }
    ll info[maxn];
    
    int main()
    {
    	//freopen("D:\code\text\input.txt","r",stdin);
    	//freopen("D:\code\text\output.txt","w",stdout);
    	n = readint();
    	repd(i, 1, n - 1)
    	{
    		int x = readint();
    		int y = readint();
    		v[x].push_back(y);
    		v[y].push_back(x);
    	}
    	dfs(1, 0, 0ll);
    	m = readint();
    	repd(i, 0, m - 1)
    	{
    		int x = readint();
    		int y = readint();
    		info[i] = (path[x] ^ path[y]);
    	}
    	int maxstate = (1 << m) - 1;
    	ll ans = 0ll;
    	repd(i, 0, maxstate)
    	{
    		ll num = 0ll;
    		int cnt = 0;
    		repd(j, 0, m - 1)
    		{
    			if (i & (1 << j)) {
    				cnt++;
    				num |= info[j];
    			}
    		}
    		int free = n - 1 - __builtin_popcountll(num);
    		ans += poww(2ll, free) * (cnt & 1 ? -1ll : 1ll);
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    实验三:Linux进程管理(HDU)
    ORA-25153错误及解决办法
    Python中的next()iter()函数详解
    python基础_格式化输出(%用法和format用法)(转载)
    DataTable ---导出Excel
    gridview-
    Web-Web/Json的请求与返回
    Sql-事务
    Windows-远程桌面
    Dev-GridView-对于gridview的列值的合计
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12370064.html
Copyright © 2011-2022 走看看