一、题目解读
2020年CSP-S(中国计算机学会青少年信息学奥林匹克竞赛)的“动物园”题目(洛谷P7076)要求计算为满足饲养员对动物属性的要求,至少需要新增多少种动物。题目涉及二进制位运算与属性匹配,考验逻辑与优化能力。
二、解题思路
采用位运算为核心策略:
属性合并:用位运算将已有动物属性整合,简化后续判断;
需求统计:标记必须存在的属性位(required)与禁止位(forbidden),动态分析约束条件;
最小数量计算:通过可选位的数量,结合特殊情况(如n=0)推导最终结果。
三、解题步骤
输入优化:禁用同步流提升效率;
属性整合:用|运算符合并所有动物属性,记录于animals变量;
处理要求:遍历饲养员需求,标记required位,若原属性不满足则禁止该位;
计算自由位:统计未被约束的位(free_bits),即新增动物的可选属性组合空间;
结果推导:根据自由位数量与特殊情况输出答案。
四、代码与注释
#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)的处理,避免结果溢出。该思路对算法竞赛中的位运算优化具有参考价值。
来源:CSP题解