제출 #1369847

#제출 시각아이디문제언어결과실행 시간메모리
1369847LOLOLOBoat (APIO16_boat)C++20
100 / 100
390 ms460 KiB
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int MOD = 1000000007;

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;
}

long long modInverse(long long n) {
    return power(n, MOD - 2);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int n;
    cin >> n;

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

    sort(coords.begin(), coords.end());
    coords.erase(unique(coords.begin(), coords.end()), coords.end());

    vector<long long> inv(n + 1);
    for (int i = 1; i <= n; i++) inv[i] = modInverse(i);

    // dp[i] là số cách chọn mà trường i là trường cuối cùng (E-most)
    // dp[0] = 1 là trạng thái cơ sở (chưa chọn trường nào)
    vector<long long> dp(n + 1, 0);
    dp[0] = 1;

    for (int j = 0; j < (int)coords.size() - 1; j++) {
        int L = coords[j + 1] - coords[j];
        
        // add[i] lưu số cách chọn mới mà trường i là trường cuối cùng TRONG khoảng này
        vector<long long> add(n + 1, 0);

        for (int i = 1; i <= n; i++) {
            // Nếu trường i có thể nằm trong khoảng hiện tại
            if (a[i] <= coords[j] && b[i] >= coords[j + 1] - 1) {
                int c = 1; // Số lượng trường có thể thuộc khoảng này tính từ p đến i
                
                // Duyệt các trường p đứng trước i (p < i)
                for (int p = i - 1; p >= 0; p--) {
                    // Tính C(L + c - 1, c)
                    // Ở đây ta tính thủ công hoặc dùng tính chất để tối ưu
                    // Tuy nhiên để dễ hiểu, ta dùng biến comb cập nhật dần
                    // Nhưng công thức tổ hợp phụ thuộc vào c, mà c tăng khi p giảm.
                    
                    // Ta cần tính C(L+c-1, c) cho mỗi bước c tăng lên
                    // Tuy nhiên, chỉ những p nào thỏa mãn điều kiện mới làm tăng c
                    
                    // Cách tính chuẩn: 
                    // Với mỗi p, ta lấy dp[p] (số cách kết thúc tại p ở các khoảng TRƯỚC đó)
                    // nhân với số cách chọn một nhóm kết thúc tại i trong khoảng NÀY.
                }
            }
        }
        
        // Tối ưu hóa vòng lặp i và p:
        for (int i = 1; i <= n; i++) {
            if (a[i] <= coords[j] && b[i] >= coords[j + 1] - 1) {
                int c = 1;
                // Tính toán tổ hợp C(L+c-1, c)
                long long comb = L; 
                
                for (int p = i - 1; p >= 0; p--) {
                    // dp[p] đại diện cho các cách đã kết thúc ở p từ các khoảng trước
                    add[i] = (add[i] + dp[p] * comb) % MOD;
                    
                    // Nếu trường p cũng có thể chèn vào khoảng này cùng với i
                    if (p > 0 && a[p] <= coords[j] && b[p] >= coords[j + 1] - 1) {
                        c++;
                        comb = comb * (L + c - 1) % MOD * inv[c] % MOD;
                    }
                }
            }
        }

        // Cập nhật dp sau khi duyệt xong toàn bộ khoảng để tránh dùng đè lên nhau
        for (int i = 1; i <= n; i++) {
            dp[i] = (dp[i] + add[i]) % MOD;
        }
    }

    long long ans = 0;
    for (int i = 1; i <= n; i++) ans = (ans + dp[i]) % MOD;
    cout << ans << endl;

    return 0;
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…