Efficient Algorithms for Dragon Slaying, Backpack Optimization, and Geometric Problems

Dragon Slayer Pathfinding with Binary Enumeration

Coordinate scaling converts decimal start/end points to integers for grid processing. Binary enumeration efficiently searches all possible wall removal combinations.

#include <iostream>
#include <vector>
#include <bitset>
using namespace std;

struct Barrier {
    int x_start, y_start, x_end, y_end;
};

const int DIR_X[] = {0, 2, 0, -2};
const int DIR_Y[] = {2, 0, -2, 0};

class DragonMap {
    int width, height, barrier_count;
    int start_x, start_y, target_x, target_y;
    vector<Barrier> barriers;
    vector<vector<bool>> visited;
    
    bool is_valid(int x, int y) {
        return x >= 0 && x < width && y >= 0 && y < height && !visited[x][y];
    }
    
    void explore_path(int x, int y, int active_walls) {
        visited[x][y] = true;
        
        for (int d = 0; d < 4; d++) {
            int nx = x + DIR_X[d];
            int ny = y + DIR_Y[d];
            int mid_x = x + DIR_X[d] / 2;
            int mid_y = y + DIR_Y[d] / 2;
            
            if (!is_valid(nx, ny)) continue;
            
            bool blocked = false;
            for (int i = 0; i < barrier_count; i++) {
                if (!(active_walls & (1 << i))) continue;
                Barrier b = barriers[i];
                
                if (b.x_start == b.x_end) {
                    if (mid_x == b.x_start && mid_y >= b.y_start && mid_y <= b.y_end) {
                        blocked = true;
                        break;
                    }
                } else {
                    if (mid_y == b.y_start && mid_x >= b.x_start && mid_x <= b.x_end) {
                        blocked = true;
                        break;
                    }
                }
            }
            
            if (!blocked) explore_path(nx, ny, active_walls);
        }
    }
    
public:
    int find_minimal_removals() {
        int min_remove = barrier_count;
        int total_combinations = 1 << barrier_count;
        
        for (int combo = 0; combo < total_combinations; combo++) {
            int removals = barrier_count - __builtin_popcount(combo);
            if (removals > min_remove) continue;
            
            visited.assign(width, vector<bool>(height, false));
            explore_path(start_x, start_y, combo);
            
            if (visited[target_x][target_y]) {
                min_remove = min(min_remove, removals);
            }
        }
        
        return min_remove;
    }
    
    void process_test_case() {
        cin >> width >> height >> barrier_count;
        cin >> start_x >> start_y >> target_x >> target_y;
        
        width *= 2; height *= 2;
        start_x = start_x * 2 + 1; start_y = start_y * 2 + 1;
        target_x = target_x * 2 + 1; target_y = target_y * 2 + 1;
        
        barriers.resize(barrier_count);
        for (int i = 0; i < barrier_count; i++) {
            cin >> barriers[i].x_start >> barriers[i].y_start 
                >> barriers[i].x_end >> barriers[i].y_end;
            barriers[i].x_start *= 2; barriers[i].x_end *= 2;
            barriers[i].y_start *= 2; barriers[i].y_end *= 2;
            
            if (barriers[i].x_start > barriers[i].x_end) 
                swap(barriers[i].x_start, barriers[i].x_end);
            if (barriers[i].y_start > barriers[i].y_end) 
                swap(barriers[i].y_start, barriers[i].y_end);
        }
        
        cout << find_minimal_removals() << endl;
    }
};

Backpack Optimizaton with XOR Maximization

Find maximum XOR value when exactly filling a backpack capacity. Bitset optimization handles state transitions efficiently.

Transition formula: [f_{i,j,k} = f_{i-1,j,k} \mid f_{i-1,j \oplus w_i,k \ll v_i}]

#include <bits/stdc++.h>
using namespace std;

const int MAX_BITS = 1024;
bitset<MAX_BITS> dp[MAX_BITS], temp[MAX_BITS];

int backpack_xor(int n, int capacity, vector<pair<int, int>>& items) {
    dp[0][0] = 1;
    
    for (auto& item : items) {
        int value = item.first, weight = item.second;
        
        for (int j = 0; j < MAX_BITS; j++) {
            temp[j] = dp[j];
            temp[j] <<= value;
        }
        
        for (int j = 0; j < MAX_BITS; j++) {
            dp[j] |= temp[j ^ weight];
        }
    }
    
    int result = -1;
    for (int j = 0; j < MAX_BITS; j++) {
        if (dp[j][capacity]) {
            result = j;
        }
    }
    
    for (int i = 0; i < MAX_BITS; i++) {
        dp[i].reset();
        temp[i].reset();
    }
    
    return result;
}

Median Distance Counting with Prime Constraints

Count triplets where median Manhattan distance is prime. Precompute primes and use bitset operations for efficient counting.

#include <bits/stdc++.h>
using namespace std;

const int MAX_N = 2000;
const int MAX_DIST = 200000;

struct Point { int x, y; };
struct Edge { int u, v, distance; };

bitset<MAX_N> adjacency[MAX_N];
bool is_prime[MAX_DIST + 1];

void sieve_primes(int n) {
    fill_n(is_prime, n + 1, true);
    is_prime[0] = is_prime[1] = false;
    
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            for (int j = i * 2; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }
}

long long count_prime_median_triplets(vector<Point>& points) {
    int n = points.size();
    vector<Edge> edges;
    
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int dist = abs(points[i].x - points[j].x) + abs(points[i].y - points[j].y);
            edges.push_back({i, j, dist});
        }
    }
    
    sort(edges.begin(), edges.end(), [](const Edge& a, const Edge& b) {
        return a.distance < b.distance;
    });
    
    for (int i = 0; i < n; i++) adjacency[i].reset();
    
    long long count = 0;
    for (auto& edge : edges) {
        int u = edge.u, v = edge.v, dist = edge.distance;
        
        if (is_prime[dist]) {
            count += (adjacency[u] ^ adjacency[v]).count();
        }
        
        adjacency[u][v] = adjacency[v][u] = true;
    }
    
    return count;
}

Special Edge Pathfinding with Teleportation

Dijkstra with layered graph handles special edges that enable teleportation to non-adjacent nodes with cost adjustment for adjacent nodes.

#include <bits/stdc++.h>
using namespace std;

const long long INF = 1e18;

struct Edge {
    int target, weight, is_special;
};

struct Node {
    int vertex, type;
    long long distance;
    bool operator<(const Node& other) const {
        return distance > other.distance;
    }
};

vector<long long> layered_dijkstra(int n, int start, int discount, vector<vector<Edge>>& graph) {
    vector<vector<long long>> dist(2, vector<long long>(n + 1, INF));
    vector<vector<bool>> visited(2, vector<bool>(n + 1, false));
    vector<int> last_visit(n + 1, 0);
    
    set<int> unvisited;
    for (int i = 1; i <= n; i++) {
        if (i != start) unvisited.insert(i);
    }
    
    priority_queue<Node> pq;
    dist[0][start] = 0;
    pq.push({start, 0, 0});
    
    int visit_count = 0;
    
    while (!pq.empty()) {
        Node current = pq.top(); pq.pop();
        int u = current.vertex, type = current.type;
        
        if (visited[type][u]) continue;
        visited[type][u] = true;
        
        if (type == 0) {
            unvisited.erase(u);
        } else {
            visit_count++;
            for (auto& edge : graph[u]) {
                last_visit[edge.target] = visit_count;
            }
            
            vector<int> teleport_nodes;
            for (int node : unvisited) {
                if (last_visit[node] != visit_count) {
                    teleport_nodes.push_back(node);
                    dist[0][node] = dist[1][u];
                    pq.push({node, 0, dist[0][node]});
                }
            }
            
            for (int node : teleport_nodes) {
                unvisited.erase(node);
            }
        }
        
        long long cost_adjust = type ? -discount : 0;
        
        for (auto& edge : graph[u]) {
            int v = edge.target, w = edge.weight, special = edge.is_special;
            long long new_dist = dist[type][u] + w + cost_adjust;
            
            if (new_dist < dist[special][v]) {
                dist[special][v] = new_dist;
                pq.push({v, special, new_dist});
            }
        }
    }
    
    vector<long long> result(n + 1);
    for (int i = 1; i <= n; i++) {
        result[i] = min(dist[0][i], dist[1][i]);
        if (result[i] == INF) result[i] = -1;
    }
    
    return result;
}

Laser Coverage Validation

Check if all points can be covered by laser beams in horizontal, vertical, or diagonal directions from a single weapon placement.

#include <iostream>
#include <vector>
using namespace std;

bool is_covered(int dx, int dy) {
    return dx == 0 || dy == 0 || dx == dy || dx == -dy;
}

bool check_coverage(int weapon_x, int weapon_y, const vector<pair<int, int>>& points) {
    for (auto& point : points) {
        int dx = weapon_x - point.first;
        int dy = weapon_y - point.second;
        if (!is_covered(dx, dy)) return false;
    }
    return true;
}

bool can_cover_all_points(vector<pair<int, int>>& points) {
    int n = points.size();
    
    vector<int> x(n), y(n);
    for (int i = 0; i < n; i++) {
        x[i] = points[i].first;
        y[i] = points[i].second;
    }
    
    for (int i = 1; i < n; i++) {
        if (x[i] == x[0]) continue;
        
        if (check_coverage(x[0], y[i], points)) return true;
        if (check_coverage(x[0], y[i] + (x[i] - x[0]), points)) return true;
        if (check_coverage(x[0], y[i] - (x[i] - x[0]), points)) return true;
        break;
    }
    
    return false;
}

bool solve_laser_problem(vector<pair<int, int>>& points) {
    if (can_cover_all_points(points)) return true;
    
    for (auto& point : points) swap(point.first, point.second);
    if (can_cover_all_points(points)) return true;
    
    for (auto& point : points) {
        int a = point.first, b = point.second;
        point.first = a + b;
        point.second = a - b;
    }
    if (can_cover_all_points(points)) return true;
    
    for (auto& point : points) {
        int a = point.first, b = point.second;
        point.first = a - b;
        point.second = a + b;
    }
    return can_cover_all_points(points);
}

Modular Probability Caclulation

Compute (n - m) / 2 mod 10^9+7 using modular inverse of 2.

#include <iostream>
using namespace std;

const int MOD = 1000000007;
const int INV_2 = 500000004; // 2^{-1} mod MOD

int compute_probability(int n, int m) {
    return (1LL * (n - m) * INV_2) % MOD;
}

Alice and Bob Game Theory

Game dteermined by whether the cumulative sum of a[i]/2^i exceeds zero.

#include <iostream>
#include <vector>
using namespace std;

string determine_winner(vector<int>& counts) {
    int n = counts.size() - 1;
    for (int i = n; i > 0; i--) {
        counts[i - 1] += counts[i] / 2;
    }
    return counts[0] > 0 ? "Alice" : "Bob";
}

Tags: algorithm Competitive Programming graph theory Dynamic Programming combinatorics

Posted on Fri, 24 Jul 2026 17:13:22 +0000 by chreez