c++ - 集合论的取组合问题

标签 c++ algorithm math combinations

给定一个大小为 N 的数组 A。数组 A 的子集的值定义为该子集中所有数字的乘积。我们必须返回数组 A %(10^9+7) 的所有可能非空子集的值的乘积。

例如数组 A {3,5}

` 值{3} = 3, 值{5} = 5, 值{3,5} = 5*3 = 15

答案 = 3*5*15 %(10^9+7)。

谁能解释一下问题背后的数学原理。我正在考虑通过组合来解决它以高效地解决它。

我试过使用蛮力,它给出了正确的答案,但速度太慢了。 下一个方法是使用组合。现在我认为如果我们把所有的集合都乘以这些集合中的所有数字,那么我们将得到正确的答案。因此,我必须找出一个数字在计算答案时出现了多少次。在示例中,5 和 3 都出现了 2 次。如果我们仔细观察,a 中的每个数字都会出现相同的次数。

最佳答案

您正朝着正确的方向前进。

x 为给定数组A 的一个元素。在我们的最终答案中,x 出现了 p 次,其中 p 等于 A 的子集数> 可能包含 x

如何计算p?一旦我们决定我们肯定会在我们的子集中包含 x ,我们对其余的 N-1 元素有两个选择:将它们包含在集合中或不包含它们。因此,我们得出结论 p = 2^(N-1)

因此,A 的每个元素在最终产品中恰好出现 2^(N-1) 次。剩下的就是计算答案:(a1 * a2 * ... * an)^p。由于指数非常大,您可以使用 binary exponentiation用于快速计算。

正如 Matt Timmermans 在下面的评论中建议的那样,我们无需实际计算 p = 2^(N-1) 即可获得答案。我们首先计算乘积 a1 * a2 * ... * an。然后,我们简单地将此乘积平方 n-1 次。

对应的C++代码:

int func(vector<int> &a) {
    int n = a.size();
    int m = 1e9+7;
    if(n==0) return 0;
    if(n==1) return (m + a[0]%m)%m;

    long long ans = 1;

    //first calculate ans = (a1*a2*...*an)%m
    for(int x:a){
        //negative sign does not matter since we're squaring
        if(x<0) x *= -1;
        x %= m;
        ans *= x;
        ans %= m;
    }

    //now calculate ans = [ ans^(2^(n-1)) ]%m
    //we do this by squaring ans n-1 times
    for(int i=1; i<n; i++){
        ans = ans*ans;
        ans %= m;
    }

    return (int)ans;
}

关于c++ - 集合论的取组合问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57253525/

相关文章:

Java:将数据拟合到 Gamma 分布(需要比例、形状)

c++ - C++中有二次编程库吗?

c++ - 如何即时更改 CDockingManager 停靠模式?

algorithm - 什么样的数学可以帮助我解决编程问题?

C++:声明对象时出现 "incomplete type is not allowed"- 原因是什么?

ruby - ruby 之和为N的K个数的可能方程的数量

algorithm - 从二进制矩阵中消除重复项。能比 O(n^2) 更及时地完成吗

python - 统计:优化python中的概率计算

c++ - QML 文本滚动

c++ - 为什么在 SFINAE 中调用该函数不会产生歧义?