Submission #1340203

#TimeUsernameProblemLanguageResultExecution timeMemory
1340203fatelessBoat (APIO16_boat)C++20
100 / 100
477 ms8352 KiB
#include <bits/stdc++.h>
using namespace std;

#define int long long
const int MOD = 1e9 + 7;

int inv[505];

// Precompute modular inverses in O(N)
void precompute_inv(int n) {
    inv[1] = 1;
    for (int i = 2; i <= n; i++) {
        inv[i] = MOD - (MOD / i) * inv[MOD % i] % MOD;
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n;
    cin >> n;

    vector<int> a(n + 1), b(n + 1), coords;
    for (int i = 1; i <= n; i++) {
        cin >> a[i] >> b[i];
        coords.push_back(a[i]);
        coords.push_back(b[i] + 1);
    }

    // Coordinate Compression
    sort(coords.begin(), coords.end());
    coords.erase(unique(coords.begin(), coords.end()), coords.end());

    precompute_inv(n + 1);

    int m = coords.size();
    // dp[i][j] = ways using a subset of first i schools, 
    // where school i MUST send boats in interval j.
    vector<vector<int>> dp(n + 1, vector<int>(m, 0));
    
    // pref[i][j] stores the sum of dp[0...i][j] for transitions
    vector<vector<int>> pref(n + 1, vector<int>(m, 0));

    // Base case: 1 way to send 0 boats (empty set)
    for (int j = 0; j < m; j++) pref[0][j] = 1;

    for (int j = 1; j < m; j++) { // For each interval [coords[j-1], coords[j])
        int W = coords[j] - coords[j - 1];

        for (int i = 1; i <= n; i++) {
            // Only process if school i can actually fit in this interval
            if (a[i] <= coords[j - 1] && b[i] >= coords[j] - 1) {
                int c = 1;
                // Ways to pick 1 school from interval W: C(W, 1)
                int current_comb = W; 
                
                for (int p = i - 1; p >= 0; p--) {
                    // Transition: 
                    // (Ways from previous schools in smaller intervals) * (Ways to clump schools in this interval)
                    int ways = (pref[p][j - 1] * current_comb) % MOD;
                    dp[i][j] = (dp[i][j] + ways) % MOD;

                    // If the previous school p could also fit in this interval, 
                    // we increment c and update our combination: C(W+c-1, c)
                    if (p > 0 && a[p] <= coords[j - 1] && b[p] >= coords[j] - 1) {
                        c++;
                        current_comb = current_comb * (W + c - 1) % MOD;
                        current_comb = current_comb * inv[c] % MOD;
                    }
                }
            }
        }

        // After processing interval j for all schools, update prefix sums for the next interval
        for (int i = 1; i <= n; i++) {
            pref[i][j] = (pref[i - 1][j] + pref[i][j - 1] - pref[i - 1][j - 1] + dp[i][j] + MOD) % MOD;
            // Simplified prefix update:
            // This just needs to track sum of all dp[0...i][0...j]
        }
        
        // Let's use a cleaner prefix sum for "all ways using schools 0...i in intervals < j"
        int total_prev_intervals = 0;
        for (int i = 0; i <= n; i++) {
            // sum of dp[i][0...j]
            pref[i][j] = (pref[i][j-1] + dp[i][j]) % MOD;
        }
    }

    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < m; j++) {
            ans = (ans + dp[i][j]) % MOD;
        }
    }

    cout << ans << endl;

    return 0;
}

// WTF
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...