← All Posts
DSA · Bit Manipulation· Part 19 of 32

Advanced Bitmask DP

Basic bitmask DP stores a subset as a state. Advanced bitmask DP uses masks to represent boundaries, compressed graph states, connectivity, or one half of a meet-in-the-middle split. These patterns are common in ICPC-style problems and hard Codeforces rounds.

Profile DP

Profile DP scans a grid cell by cell or row by row. A mask represents the current frontier: which cells in the next few positions are already occupied or connected.

// Domino tiling sketch: recursively fill one row profile.
void gen(int col, int cur, int next, vector<pair<int,int>>& trans) {
    if (col == W) {
        trans.push_back({cur, next});
        return;
    }
    if (cur & (1 << col)) {
        gen(col + 1, cur, next, trans);
        return;
    }
    // vertical domino affects next row
    gen(col + 1, cur | (1 << col), next | (1 << col), trans);
    // horizontal domino inside current row
    if (col + 1 < W && !(cur & (1 << (col + 1)))) {
        gen(col + 2, cur | (1 << col) | (1 << (col + 1)), next, trans);
    }
}

Connected Subset DP

Some graph problems require DP over subsets that form connected components. Precompute connectivity or grow states only by adding adjacent vertices.

bool connected[1 << N];
connected[0] = false;
for (int mask = 1; mask < (1 << N); ++mask) {
    int v = __builtin_ctz(mask);
    int rest = mask ^ (1 << v);
    connected[mask] = rest == 0 || ((adj[v] & rest) && connected[rest]);
}

The exact recurrence depends on the graph property, but the idea is always to avoid considering impossible disconnected states.

Meet-in-the-Middle with Masks

When n is around 40, 2^n is impossible but 2^(n/2) is feasible. Split the items into two halves, enumerate each half, then combine.

vector<long long> sums(vector<int> a) {
    int n = a.size();
    vector<long long> out;
    for (int mask = 0; mask < (1 << n); ++mask) {
        long long s = 0;
        for (int i = 0; i < n; ++i)
            if (mask & (1 << i)) s += a[i];
        out.push_back(s);
    }
    return out;
}

Memory Optimization

Pruning and Dominance

In many state-compression searches, one state dominates another if it has the same mask and a better cost/resource tuple. Keep only the best representative.

// Example: dp[mask] = minimum cost seen for this exact mask.
if (new_cost < dp[new_mask]) {
    dp[new_mask] = new_cost;
    push(new_mask);
}

Recognition Guide

Practice Problems