题解:洛谷 P2415 集合求和
【题目来源】
洛谷:P2415 集合求和 - 洛谷(luogu.com.cn)
【题目描述】
给定一个集合 \(s\)(集合元素数量 \(\le 30\)),求出此集合所有子集元素之和。
【输入】
集合中的元素(元素 \(\le 1000\))
【输出】
\(s\) 所有子集元素之和。
【输入样例】
2 3
【输出样例】
10
【核心思想】
-
问题分析:给定一个包含不超过 30 个元素的集合 \(s\),需要计算该集合所有子集的元素之和。每个元素在多少个子集中出现?对于包含 \(n\) 个元素的集合,每个元素出现在 \(2^{n-1}\) 个子集中(因为对于该元素之外的 \(n-1\) 个元素,每个都可以选择出现或不出现)。因此,所有子集元素之和 = 集合元素总和 \(\times 2^{n-1}\)。本质是组合数学问题,利用每个元素出现次数的对称性。
-
算法选择:
- 数学公式:直接计算元素总和
sum和元素个数n,答案即为sum * 2^(n-1)。由于 \(n \le 30\),\(2^{29}\) 在long long范围内,无需高精度。 - 读入处理:使用
while(cin >> a)循环读取所有元素,直到输入结束。
- 数学公式:直接计算元素总和
-
关键步骤:
- 读取与累加:使用循环读入每个元素
a,累加到ans,并计数k++。 - 计算答案:
ans *= pow(2, k-1)(或使用左移1 << (k-1))。 - 输出:输出
ans。
- 读取与累加:使用循环读入每个元素
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),\(n\) 是元素个数。
- 空间复杂度:\(O(1)\)。
-
组合计数与幂运算:
- 核心公式:每个元素在所有子集中出现的次数为 \(2^{n-1}\),所以总和为
sum * 2^(n-1)。 - 幂运算:
pow(2, k-1)返回double,但结果在整数范围内,可直接用1LL << (k-1)更精确。 - 适用场景:这类“集合子集求和”问题,核心是发现每个元素的出现次数规律,避免枚举所有子集。
- 核心公式:每个元素在所有子集中出现的次数为 \(2^{n-1}\),所以总和为
【算法标签】
普及- #数学
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
long long ans; // 定义变量:存储最终结果(使用long long防止溢出)
int a, k = 0; // 定义变量:a存储当前输入数字,k统计输入数字个数
int main()
{
// 循环读取输入的数字,直到输入结束
while (cin >> a)
{
ans += a; // 累加所有输入数字的和
k++; // 统计输入数字的个数
}
// 计算结果:总和乘以2的(k-1)次方
ans = (long long)ans * pow(2, k - 1);
// 输出最终结果
cout << ans << endl;
return 0; // 程序正常结束
}
【运行结果】
2 3
^Z
10
浙公网安备 33010602011771号