P2036 PERKET
P2036 PERKET
解题思路
本题本质是一个 子集枚举问题(位运算)。
每种食材有两种状态:选 / 不选
因此一共有 2^n 种选择方案。
我们可以用一个整数 mask 的二进制表示一种选择方案:
- 第 i 位为 1 → 选第 i 个食材
- 第 i 位为 0 → 不选
例如(n = 2):
| mask | 二进制 | 选择情况 |
|---|---|---|
| 0 | 00 | 空集(不合法) |
| 1 | 01 | 选第0个 |
| 2 | 10 | 选第1个 |
| 3 | 11 | 全选 |
1. 枚举所有子集
for (int mask = 1; mask < (1 << n); mask++)
1 << n表示 2^n- 从 1 开始是为了排除空集
2. 判断某一位是否被选中
if (mask & (1 << i))
含义:
- 不为 0 → 选了
- 为 0 → 没选
3. 计算当前子集的值
- 酸度:乘积(初始为 1)
- 苦度:加和(初始为 0)
long long x = 1, y = 0;
4. 更新答案
ans = min(ans, abs(x - y));
复杂度分析
- 时间复杂度:O(n * 2^n)
- 空间复杂度:O(n)
代码实现
void solve() {
int n;
cin>>n;
vector<int>s(n),b(n);
rep(i,0,n) cin>>s[i]>>b[i];
LL ans=MAX;
rep(mask,1,1<<n){
LL x=1,y=0;
rep(i,0,n){
if(mask&(1<<i)){
x*=s[i];
y+=b[i];
}
}
ans=min(ans,abs(x-y));
}
cout<<ans<<'\n';
}
易错点总结
- 每个子集必须重新初始化x为1,y为0
- 不能包含空集mask=1
- 酸度初始必须为1
- 复杂度是 O(n * 2^n)
总结
用二进制枚举所有非空子集,每一位表示选或不选,暴力求最优解。

浙公网安备 33010602011771号