2020CSP-S动物园题解:位运算优化解法(洛谷P7076)
一、题目解读
2020年CSP-S(中国计算机学会青少年信息学奥林匹克竞赛)的“动物园”题目(洛谷P7076)要求计算为满足饲养员对动物属性的要求,至少需要新增多少种动物。题目涉及二进制位运算与属性匹配,考验逻辑与优化能力。
二、解题思路
采用位运算为核心策略:
1. 属性合并:用位运算将已有动物属性整合,简化后续判断;
2. 需求统计:标记必须存在的属性位(required)与禁止位(forbidden),动态分析约束条件;
3. 最小数量计算:通过可选位的数量,结合特殊情况(如n=0)推导最终结果。
三、解题步骤
1. 输入优化:禁用同步流提升效率;
2. 属性整合:用|运算符合并所有动物属性,记录于animals变量;
3. 处理要求:遍历饲养员需求,标记required位,若原属性不满足则禁止该位;
4. 计算自由位:统计未被约束的位(free_bits),即新增动物的可选属性组合空间;
5. 结果推导:根据自由位数量与特殊情况输出答案。
四、代码与注释
#include <iostream> #include <vector> #include <algorithm> using namespace std; /* * 解题思路: * 1. 使用位运算处理动物属性 * 2. 统计每个二进制位上的需求情况 * 3. 计算满足所有饲养员要求的最小动物数量 */ int main() { // 输入优化 ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, c, k; cin >> n >> m >> c >> k; // 读取已有动物属性 unsigned long long animals = 0; for (int i = 0; i < n; ++i) { unsigned long long a; cin >> a; animals |= a; // 合并所有动物的属性 } // 处理每个二进制位 vector<bool> required(k, false); vector<bool> forbidden(k, false); // 处理饲养员要求 for (int i = 0; i < m; ++i) { int p, q; cin >> p >> q; required[p] = true; // 标记该位有要求 // 如果已有动物不满足该位要求,则禁止该位为1 if (!(animals & (1ULL << p))) { forbidden[p] = true; } } // 计算可选位数 int free_bits = 0; for (int i = 0; i < k; ++i) { if (!required[i] || (required[i] &&!forbidden[i])) { free_bits++; } } // 计算结果(注意处理n=0的特殊情况) if (free_bits == 64 && n == 0) { cout << "18446744073709551616" << endl; } else { cout << (1ULL << free_bits) - n << endl; } return 0; }
五、总结
本解法巧妙利用位运算将属性转化为二进制位操作,通过约束条件的动态分析,高效解决组合计数问题。特别需注意边界情况(如n=0)的处理,避免结果溢出。该思路对算法竞赛中的位运算优化具有参考价值。
原创内容 转载请注明出处