• 集合幂级数垃圾题选讲


    可能更好的阅读体验


    CF449D Jzzhu and Numbers

    首先可以发现这是一个背包,列出最基本的dp子状态:(dp_{i,j}) 代表前 (i) 个数的子集(包括空集)组合出 (j) 的方案数,有方程 (dp_{i,j}=dp_{i-1,j}+sum_{k & a_i=j}dp_{i-1,k})

    在考虑优化之前先想一想初值,发现与运算的话有 (dp_{0,(1<<|U|)}=1),也就是全集为 (1)。到此我们可以开始优化,我们发现每次转移可以看成和一个第 (a_i) 这个集合和全集为 (1),其他为 (0) 的幂级数做卷积,每次可以用FMT来实现,可是这样并没有加快速度。这里给出伪代码(一点都不伪了):

    f[2^M-1]=1;
    FMT(f,1);
    //全集为1,FMT后每一个都是1,因为FMT本质上是一个高维后缀和
    for (i : 1 -> n) {
        g[j] -> 0;
        g[a[i]]++; g[2^k-1]++;
        FMT(g,1);
        for (j : 0 -> 2^k-1) f[j] *= g[j];
    }
    FMT(f, -1);
    return f[0];
    

    然后我们发现每次 (g[j]) 要么是 (1) 要么是 (2)然后开始猜结论,这是可以严格证明的,也很简单,因为是做后缀和,所以超集有 (a[i]) 的就会加上 (1),而全集是每个集合的超集所以每个集合也会再加上 (1)

    那这下就好办了,每次只会有部分集合乘以 (2),那么我们是不是只要统计出每个集合会乘多少次 (2) 即可。怎么算?其实也就是每个集合有多少个 (a[i]) 是他的超集,直接FMT高维后缀和就好。注意这样会把空集也统计进去所以最后要减去 (1)。最后再反演回去即可得到答案((dp_{n,0}))。

    其实这道题还可以考虑为从所以是某个值的超集的数所组成的集合中取一个子集(不算空集)。所以是 (2^{G[i]}-1)。再反演回去即为答案。

    code

    CF662C Binary Table

    考虑 (n) 非常的小,那么我们可以把每一列的状态压缩成一个整数。考虑只能把每列里的01取反,那么对于每一列的状态 (s) 答案显然是 (min(count(s),n-count(s))),其中 (count(s)) 代表 (s) 二进制表示下 (1) 的个数。

    再考虑每行的操作,发现只有操作或不操作两种情况,所以也可以压缩。记 (ans_k) 代表操作情况是 (k) 时的答案,而 (k) 的二进制表示下每一位的 (1) 代表这一行全部取反,对于一列 (s),进行了 (k) 这个操作后的表示即为 (kigoplus s)。记 (mn_s=min(count(s),n-count(s)))(cnt_s) 表示在没有行操作时列上状态为 (s) 的个数。然后有 (ans_k=sumlimits_{kigoplus s=t}cnt_s imes mn_t),根据异或的性质:(aigoplus b=cRightarrow aigoplus c=b),可以将方程转换为 (ans_k=sumlimits_{sigoplus t=k}cnt_s imes mn_t),就是一个异或卷积的形式,直接上FWT即可。

    code

    CF914G Sum the Fibonacci

    怎么说呢,这题就是个模板大合一。

    发现题目要求的东西就是把 (f(s_a|s_b),f(s_c),f(s_digoplus s_e)) 集合并卷积卷到一起后 (2^i) 的值的和。所以我们只需要求出 (s_a|s_b,s_c,s_digoplus s_e) 的个数即可。又发现题目要求 (s_a&s_b=0) 所以是个子集卷积,后面那个可以用集合对称差卷积来做。这样卷完算出个数再套个斐波那契数最后再集合并卷积卷起来就是答案。

    code

    CF1034E Little C Loves 3 III

    这是一道代码和结论都非常简单不过比较难想的妙妙题。

    我们发现这就是个子集卷积的模板但是复杂度不太允许。我们回忆一下子集卷积的过程,要把第二维拆成一个普通卷积,这在这道题里直接给了我们一个思路,因为要对 (4) 取模,所以我们不妨给每个 (i) 乘上一个 (4^{popcount(i)),这样子对于两个数 (i,j),做或卷积后为 (f_i imes f_j imes 4^{popcount(i)+popcount(j)}),如果 (j&i=0),那么 (popcount(i)+popcount(j)=popcount(i|j)),所以我们给其除以一个 (popcount(i|j)),如果有剩余(不为 (1),这个的值一定是 (4^k,kin N)),那么模 (4) 之后就是 (0) 就不会被统计进答案了。还有个问题,这样直接做会炸longlong,我们可以对 (2^{64}) 取模,即用自然溢出。

    code

  • 相关阅读:
    第三篇:python函数
    第二篇:数据类型
    第一篇:初识python
    PyTorch教程之Autograd
    PyTorch教程之Tensors
    如何解决Python.h:No such file or directory
    如何解决conda install:command not found问题
    Linux 安装Anaconda 4.4.0
    Linux安装pytorch的具体过程以及其中出现问题的解决办法
    Writing Science 7.10 (The Opening and The Funnel)
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14164527.html
Copyright © 2020-2023  润新知