zoukankan      html  css  js  c++  java
  • SPOJ11469 Subset(折半枚举)

    题意

    给定一个集合,有多少个非空子集,能划分成和相等的两份。$nleq 20$

    题解

    看到这个题,首先能想到的是$3n$的暴力枚举,枚举当前元素是放入左边还是放入右边或者根本不放,但是显然是不可取的,看到$n$只有20,考虑折半搜索,将集合分成两部分,每个部分$3{frac{n}{2}}$枚举。

    接着考虑如何合并,在枚举时计一个$delta$表示此时左边和右边的差值,这样在右半部分每一次枚举完后我们可以直接在左半部分查找是否存在一个$delta$相等,如果相等,则两个集合的并集满足条件

    #include <map>
    #include <vector>
    #include <cstdio>
    typedef long long ll;
    
    template <typename T>
    inline void read(T &x) {
        x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    }
    
    const int N = 21;
    int n, m, a[N], cnt, ans;
    std::map <int, int> Ma;
    std::vector <int> S[1 << N];
    bool ok[1 << N];
    
    void dfs1(int i, int s, int d) {
        if (i > m) {
        if (Ma.find(d) == Ma.end()) Ma[d] = ++cnt;
        int index = Ma[d];
        //记录delta,由于可能存在多个相等的delta,开一个vector记下它是哪个集合(状态压缩)
        S[index].push_back(s);
        return ;
        }
        dfs1(i + 1, s, d);
        dfs1(i + 1, s | (1 << i), d + a[i]);
        dfs1(i + 1, s | (1 << i), d - a[i]);
    }
    
    void dfs2(int i, int s, int d) {
        if (i > n) {
        if (Ma.find(d) == Ma.end()) return ;
        int index = Ma[d];
        std::vector<int>::iterator it;
        //直接查询然后置他们的并集为真即可
        for (it = S[index].begin(); it != S[index].end(); ++it)
            ok[*it | s] = true;
        return ;
        }
        dfs2(i + 1, s, d);
        dfs2(i + 1, s | (1 << i), d + a[i]);
        dfs2(i + 1, s | (1 << i), d - a[i]);
    }
    
    int main () {
        read(n); m = n >> 1;
        for(int i = 1; i <= n; ++i) read(a[i]);
        dfs1(1, 0, 0);
        dfs2(m + 1, 0, 0);
        for(int i = (1 << (n + 1)) - 1; i >= 1; --i)
        ans += ok[i];
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    Burnside引理与Polya定理 学习笔记
    Codeforces 438E. The Child and Binary Tree 多项式,FFT
    Berlekamp_Massey 算法 (BM算法) 学习笔记
    UOJ#335. 【清华集训2017】生成树计数 多项式,FFT,下降幂,分治
    UOJ#73. 【WC2015】未来程序 提交答案题
    UOJ#206. 【APIO2016】Gap 构造 交互题
    虚拟机配置JAVA_HOME
    创建虚拟机
    月份、季度、周
    maven多模块下使用JUnit进行单元测试
  • 原文地址:https://www.cnblogs.com/water-mi/p/9798624.html
Copyright © 2011-2022 走看看