所有子集的乘积之和,

use*_*235 3 algorithm combinatorics number-theory polynomials

我想计算给定$ N $元素集的每个子集的乘积之和.例如,给定集合{1,2,3},答案是1 + 2 + 3 + 1*2 + 1*3 + 2*3 + 1*2*3.我还想给出模数$ $ M $.

我所知道的是我可以计算$(x - a_1)(x - a_2)...(x - a_n) - 1 $,但这会涉及FFT,因此可能存在一些舍入误差,但主要问题是这个想法是需要$ O(N\log ^ 2 N)$时间并且模数$ M $是有问题的.有没有更快的方法来解决这个问题?这不是我的功课,我从老师那里得到了这个任务来练习编程比赛,但我真的遇到了这个问题.

约束:

$ a_i\le 10 ^ 9 $

$ N\le 10 ^ 6 $

$ M\le 10 ^ 9 $

Joh*_*man 5

有问题的是

[(1+a_1)*(1+a_2)*(1+a_3)*...*(1+a_N) - 1] (mod M)
Run Code Online (Sandbox Code Playgroud)

这是

[(1+a_1)%M * (1+a_2)%M * ... * (1+a_N)%M - 1] % M
Run Code Online (Sandbox Code Playgroud)

如果你能做得更好,我会感到惊讶.

这是一个Python实现:

def sumProducts(nums, M):
    p = 1
    for num in nums:
        p = p*((1+num)%M)%M
        if p == 0:
            return M-1
    return (p-1)%M
Run Code Online (Sandbox Code Playgroud)

我上面给出的天真公式的优化是用每个新因子得到产品的模数,如果遇到零则使产品短路 - 如果主要因素(按照多重性计算)出现在该 (1 + a_i)

一个简单的测试:

>>> sumProducts([1,2,3],5)
3
Run Code Online (Sandbox Code Playgroud)

这很容易用手验证.

压力测试:

>>> from random import randint
>>> nums = [randint(1,1000000) for i in range(100000)]
Run Code Online (Sandbox Code Playgroud)

nums 是一百万到一百万的随机数

当然,

>>> sumProducts(nums,2**32)
4294967295
Run Code Online (Sandbox Code Playgroud)

由于存在在至少32个奇数nums(因此32号a_i为哪些1+a_i是偶数).

另一方面,1000003是一个大于1000000的素数,因此计算不会短路:

>>> sumProducts(nums,1000003)
719694
Run Code Online (Sandbox Code Playgroud)

计算需要一秒钟.