Submission #1358321

#TimeUsernameProblemLanguageResultExecution timeMemory
1358321yogesh_saneLego Wall (EGOI22_legowall)C++20
100 / 100
25 ms14036 KiB
#include <iostream>
#include <vector>

using namespace std;

/**
 * Problem: Lego Wall
 * Goal: Find the number of solid walls of height H and width W.
 * A wall is "solid" if no vertical line cuts through it completely.
 */

long long H, W;
const int MOD = 1e9 + 7;

// Helper function for modular exponentiation: (base^exp) % MOD
long long power(long long base, long long exp) {
    long long res = 1;
    base %= MOD;
    while (exp > 0) {
        if (exp % 2 == 1) res = (res * base) % MOD;
        base = (base * base) % MOD;
        exp /= 2;
    }
    return res;
}

/**
 * Approach 1: Used when Width is small (W < 5000).
 * Uses DP + Inclusion-Exclusion.
 */
void solve_small_width() {
    // total_ways_row[i] = number of ways to fill a 1 x i row with 1x1 and 1x2 bricks
    // This is essentially the Fibonacci sequence.
    vector<long long> total_ways_row(W + 1);
    total_ways_row[0] = 1;
    total_ways_row[1] = 1;
    for (int i = 2; i <= W; i++) {
        total_ways_row[i] = (total_ways_row[i - 1] + total_ways_row[i - 2]) % MOD;
    }

    // wall_combinations[i] = total ways to build a wall of height H and width i
    // Each of the H rows is independent, so it's (ways_per_row)^H
    vector<long long> wall_combinations(W + 1);
    for (int i = 1; i <= W; i++) {
        wall_combinations[i] = power(total_ways_row[i], H);
    }

    // solid_walls[i] = number of walls of width i that are "solid"
    // Calculation: Total combinations - Non-solid combinations
    vector<long long> solid_walls(W + 1);
    for (int i = 1; i <= W; i++) {
        solid_walls[i] = wall_combinations[i];
        for (int j = 1; j < i; j++) {
            // Subtract walls where the FIRST vertical seam occurs at position j
            long long non_solid = (solid_walls[j] * wall_combinations[i - j]) % MOD;
            solid_walls[i] = (solid_walls[i] - non_solid + MOD) % MOD;
        }
    }

    cout << solid_walls[W] << endl;
}

/**
 * Approach 2: Used when Height is small (H < 105).
 * Uses DP based on "bridging" bricks between columns.
 */
void solve_small_height() {
    // Precompute Binomial Coefficients (nCr)
    vector<vector<long long>> nCr(H + 1, vector<long long>(H + 1, 0));
    for (int i = 0; i <= H; i++) {
        nCr[i][0] = 1;
        for (int j = 1; j <= i; j++) {
            nCr[i][j] = (nCr[i - 1][j - 1] + nCr[i - 1][j]) % MOD;
        }
    }

    // dp[col][bridges] = ways to have 'bridges' number of 2x1 bricks 
    // crossing from current column to the next column.
    vector<vector<long long>> dp(W, vector<long long>(H + 1, 0));

    // Base case: First column gap (between col 1 and col 2)
    for (int j = 1; j <= H; j++) {
        dp[1][j] = nCr[H][j];
    }

    // Transition through each column
    for (int i = 2; i < W; i++) {
        for (int j = 1; j <= H; j++) { // bridges to the next column
            for (int k = 1; k <= H - j; k++) { // bridges from the previous column
                // We can only place a bridge in a row that doesn't already have one
                long long ways = (dp[i - 1][k] * nCr[H - k][j]) % MOD;
                dp[i][j] = (dp[i][j] + ways) % MOD;
            }
        }
    }

    // Sum all ways to reach the final column gap with at least one bridge
    long long total_solid_walls = 0;
    for (int j = 1; j <= H; j++) {
        total_solid_walls = (total_solid_walls + dp[W - 1][j]) % MOD;
    }

    cout << total_solid_walls << endl;
}

int main() {
    // Fast I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    if (!(cin >> W >> H)) return 0;

    // The original code switches logic based on constraints
    if (W < 5000) {
        solve_small_width();
    } else {
        solve_small_height();
    }

    return 0;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...