注释很详细

#include <bits/stdc++.h>
#define FIO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
typedef long long int ll;
ll n, m, impo[30];
int main() {
    FIO;
    cin>>n>>m;
    for(int i = 1; i <= n; i++){
        cin>>impo[i];
    }
    ll ans = 0;//初始的钥匙数为0
    for(int i = 0; i < (1 << n); i++){
        //从0遍历到2^n-1
        //从二进制来看,就是从000...0(n个)遍历到111...1(n个)
        //我们把1视作这个人在场,0视作这个人不在场
        ll cur_sum = 0;//记录在场的人的重要度之和
        ll min_impo = 999999999999;//记录所有不到场的人中重要度的最小值
        for(int j = 0; j < n; j++){
            if((1 << j) & i){
                //1 << j的二进制是只有第j+1位为1,其余都为0,
                // 只有i的2进制第j+1位为1, 这个值才可能为true
                cur_sum += impo[j + 1];
            }else{
                //i的二进制的第j+1位为0
                min_impo = min(min_impo, impo[j + 1]);
            }
        }
        if(cur_sum >= m){
            //已经到场的人的重要性已达标,一定可以打开门,直接跳过
            continue;
        }else{
            //已经到场的人的重要性不达标
            if(cur_sum + min_impo >= m){
                //再来一个人,重要性一定就达标了,就一定可以打开房门
                //就说明未在场的人都拥有至少一把在场的人都没有的钥匙
                //那么就给未在场的人每人一把新钥匙,钥匙数+1
                ans++;
                //而且因为每次遍历,在场的人都不一样,就保证了每次都必须给一把新钥匙才能满足题意
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}