zoukankan      html  css  js  c++  java
  • 【Topcoder 12004】SetAndSet 容斥+并查集

    题意

    Topcoder 12004
    把一堆数分成两堆,要求这两堆各自的按位与和相等,求分的方案数。
    ((n le 50, 0 le A_i < 2^ {20}))

    题解

    注意到这个 (A_i) 很小, (n) 也很小,看起来适合状压、容斥。
    考虑容斥各二进制位,如果一个位置被钦定不合法,那么这位上所有的(0)都属于同一个联通块(一个位置合法,当且仅当所有数该位都是1或者两堆各自至少有一个0)
    并查集维护,最后统计。
    不开long long见祖宗!

    代码

    code
    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    typedef long long ll;
    const int N = 55, lim = 21;
    class SetAndSet{
    	public: 
    	int n, fa[lim][N], cnt[lim], id[lim][N]; ll ans;
    	int find(int pos, int x){
    		return fa[pos][x] = ((x == fa[pos][x]) ? x : find(pos, fa[pos][x]));
    	}
    	bool merge(int pos, int x, int y){
    		int fx = find(pos, x), fy = find(pos, y);
    		if(fx == fy) return 0;
    		fa[pos][fx] = fy; return 1;
    	}
    	void dfs(int pos, int num, int op){
    		if(pos == lim)
    			return ans += op * ((1ll << num) - 2), void();
    		if(pos == 0){
    			for(int i = 0; i < n; i++) fa[pos][i] = i;
    		} else {
    			for(int i = 0; i < n; i++) fa[pos][i] = fa[pos - 1][i];
    		}
    		dfs(pos + 1, num, op);
    		if(cnt[pos]){
    			for(int i = 2; i <= cnt[pos]; i++)
    				if(merge(pos, id[pos][i], id[pos][1])) num--;
    			dfs(pos + 1, num, -op); 
    		} 
    	}
    	ll countandset(vector<int> A){
    		n = A.size(); ans = 0;
    		for(int i = 0; i < lim; i++){
    			cnt[i] = 0;
    			for(int j = 0; j < n; j++)
    				if(!((A[j] >> i) & 1))
    					id[i][++cnt[i]] = j;
    		} 
    		dfs(0, n, 1);
    		return ans;
    	}
    };
    /*
    O(2^20*nlogn)
    十年OI一场空,没开longlong见祖宗
    */
    
    qaqaq
  • 相关阅读:
    eos合约案例导读
    eos TODO EOS区块链上EOSJS和scatter开发dApp
    电脑提示‘您需要来自Administration的权限才能对此文件夹进行更改’怎么删除文件
    ubuntu 设置全局代理
    eos开发实践
    eos博客
    如何在Ubuntu 18.04上安装Go
    parity密码
    Nodejs基础之redis
    完全搞懂事件
  • 原文地址:https://www.cnblogs.com/zdsrs060330/p/14940167.html
Copyright © 2011-2022 走看看