zoukankan      html  css  js  c++  java
  • CF 623 E. Transforming Sequence 题解

    首先可以发现由于(b_i=b_{i-1}or a_i),所以(b)一定是不减的。而要满足(b)递增,只需要满足(b_i eq b_{i-1})就可以了。

    (b_i eq b_{i-1}),则存在一个二进制位(j),满足(a_i)的第(j)位为1,所有(a_k,(k<i))(j)位为(0)

    所以我们可以把每一个二进制位看作一个物品,每一数如果在这一位上有一个1,则代表选择了这个物品。而每一个数都必须选择了一个物品,前面的都没选过。

    所以若(N>K)则一定为0。

    所以就可以想到一个dp状态,(dp_{i,j})表示前i个人选择了j个的方案数。

    转移也比较简单:

    [dp_{i,j}=dp_{i-1,j-z} imes C_{k-(j-z)}^z imes 2^{j-z} ]

    但是这个转移是(O(N^3))的没办法通过。

    但是仔细观察一下这个式子,转移(dp_{i,j})是和(i)无关的,只和(j,z)有关。

    所以可以考虑分治,(dp_{i,j})表示总共(i)个选择(j)个的方案数。

    然后发现可以将(dp_{A,j},dp_{B,z})合并到(dp_{A+B,j+z})

    [dp_{A+B,j+z}+=dp_{A,j} imes dp_{B,z} imes 2^{jcdot B} imes C_{z+j}^j ]

    (C_{A+B}^A)写成分数的形式。

    [dp_{A+B,j+z}+=dp_{A,j}/j! imes dp_{B,z}/z! imes 2^{jcdot B} imes (z+j)! ]

    可以发现这个阶乘是和(dp_{i,j})中的(j)有关的。所以可以定义一个新的(dp'_{i,j}=dp_{i,j}/j!)

    转移就变得简单很多了。

    [dp'_{A+B,z}=sum dp'_{A,j} imes 2^{jcdot B} imes dp'_{A,z-j} ]

    这样就有了卷积形式。

    如果每次枚举(A=lfloor i/2 floor),然后递归下去,总复杂度为(O(N imes log^2n))

    由于这题模数不是ntt模数,所以需要用三个ntt模数分别计算,然后用crt合并。也可以用更快的mtt。

  • 相关阅读:
    C++中的空类默认产生哪些类成员函数
    Berkeley Socket API – Creating a TCP/IP client in C
    覆盖父类以及using指令
    strcpy/memcpy/memmove的实现
    [C++对象模型][1]目录与参考
    用setsockopt()来控制recv()与send()的超时
    异常安全的赋值运算符重载函数
    伤不起的指针
    DP01背包
    证明一个数能被3整除,当且仅当它的各位数的和能被3整除
  • 原文地址:https://www.cnblogs.com/gary-2005/p/14306350.html
Copyright © 2011-2022 走看看