01背包,但是bit -枚举 + 位运算

题面

分析

思考什么情况可以装,如果一个数或进去不超过 m m m 就可以加入,否则不能加入,那么如果某一个数和 m m m 或运算能够分为两部分,前一部分进行或运算为 m m m 的子集,后一部分可以是任何数,存在当前一位为 0 0 0,但 m m m 的这一位为 1 1 1,呢么无论如何他都是小于 m m m 的,就一定可以加进去,所以可以枚举所有 m m m 的二进制位,如果当前这一位为 1 1 1,那么可以去枚举所有的物品,如果满足当前位前面为 m m m 对应部分子集,当前位为 0 0 0 ,那么可以加进去,对所有情况取最大值。

代码
#include 

using namespace std;
using ll = long long;

const int N = 1e5 + 10;

int v[N], w[N];

void solve() {
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) cin >> w[i] >> v[i];
    ll ans = 0;
    for(int i = 0; i <= 30; i ++) {
        if(((m >> i) & 1) || i == 0) {
            int x = (1 << i) - 1;
            int res = m | x;
            ll sum = 0;
            //cout << i << endl;
            for(int j = 1; j <= n; j ++) {
                if(((v[j] >> i) & 1) && i != 0) continue;
                //cout << v[j] << ' ' << (v[j] | res) << endl;
                if((v[j] | res) == res) sum += w[j];
            }
            //cout << sum << ' ';
            ans = max(ans, sum);
        }
    }
    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int T;
    cin >> T;
    while(T --) {
        solve();
    }
}

你可能感兴趣的:(算法,c++,思维)