Submission #1180948

#TimeUsernameProblemLanguageResultExecution timeMemory
1180948ericl23302Skyscraper (JOI16_skyscraper)C++20
100 / 100
68 ms51528 KiB
#include <iostream>
#include <vector>
#include <algorithm>

#include <cstdlib>
#include <map>

#define int long long

using namespace std;

// int code(int n, int l, vector<int> &heights) {
//     sort(heights.begin(), heights.end());
//     heights.push_back(1001);
//     vector<vector<vector<vector<int>>>> dp(n + 1, vector<vector<vector<int>>>(n + 1, vector<vector<int>>(l + 1, vector<int>(3, 0))));
//     dp[0][0][0][0] = 1;
//     for (int i = 1; i <= n; ++i) {
//         for (int j = 1; j <= i; ++j) {
//             for (int k = 0; k <= l; ++k) {
//                 for (int e = 0; e < 3; ++e) {
//                     // cout << i << ' ' << j << ' ' << k << ' ' << e << '\n';
//                     if (i + j - e > n || k < (2 * j - e) * (heights[i] - heights[i - 1]) || (i < n && j == 1 && e == 2)) continue;
//                     // cout << "if\n";
//                     int newTot = k - (2 * j - e) * (heights[i] - heights[i - 1]);

//                     // case 1: adding new building as new segment not at edge
//                     dp[i][j][k][e] += dp[i - 1][j - 1][newTot][e];
//                     // cout << "case 1\n";

//                     // case 2: adding new building as new segment at edge
//                     if (e) dp[i][j][k][e] += (3 - e) * dp[i - 1][j - 1][newTot][e - 1];
//                     // cout << "case 2\n";

//                     // case 3: adding new building onto segment, not merging segments, not onto edge
//                     dp[i][j][k][e] += (2 * j - e) * dp[i - 1][j][newTot][e];
//                     // cout << "case 3\n";

//                     // case 4: adding new building onto segment, at edge
//                     if (e == 1) dp[i][j][k][e] += 2 * j * dp[i - 1][j][newTot][e - 1];
//                     else if (e == 2) {
//                         if (j == 1) dp[i][j][k][e] += dp[i - 1][j][newTot][e - 1];
//                         else dp[i][j][k][e] += (j - 1) * dp[i - 1][j][newTot][e - 1];
//                     }
//                     // cout << "case 4\n";

//                     // case 5: adding new building onto segment, merging two
//                     if (j < n) {
//                         if (e == 0) dp[i][j][k][e] += j * (j + 1) * dp[i - 1][j + 1][newTot][e];
//                         else if (e == 1) dp[i][j][k][e] += j * j * dp[i - 1][j + 1][newTot][e];
//                         else if (j == 1) dp[i][j][k][e] += dp[i - 1][j + 1][newTot][e];
//                         else dp[i][j][k][e] += j * (j - 1) * dp[i - 1][j + 1][newTot][e];
//                     }
//                     // cout << "case 5\n";

//                     dp[i][j][k][e] %= 1'000'000'007;
//                     // cout << i << ' ' << j << ' ' << k << ' ' << e << ' ' << dp[i][j][k][e] << '\n';
//                 }
//             }
//         }
//     }

//     int res = 0;
//     for (int i = 0; i <= l; ++i) {
//         res += dp[n][1][i][2];
//         res %= 1'000'000'007;
//     }

//     heights.pop_back();

//     return res;
// }

// int bruteforce(int n, int l, vector<int> &heights) {
//     sort(heights.begin(), heights.end());
//     int res = 0;
//     do {
//         int cur = 0;
//         for (int i = 0; i < n - 1; ++i) cur += abs(heights[i] - heights[i + 1]);
//         res += (cur <= l);
//     } while (next_permutation(heights.begin(), heights.end()));

//     return res;
// }

signed main() {

    ios_base::sync_with_stdio(0);
    cin.tie(0);

    int n, l; cin >> n >> l;
    if (n == 1) {
        cout << 1 << '\n';
        return 0;
    }
    vector<int> heights(n);
    for (int &i : heights) cin >> i;
    sort(heights.begin(), heights.end());
    heights.push_back(1001);
    // vector<vector<vector<vector<int>>>> dp(n + 1, vector<vector<vector<int>>>(n + 1, vector<vector<int>>(l + 1, vector<int>(3, 0))));
    static int dp[101][101][1001][3] {0};

    dp[0][0][0][0] = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= i; ++j) {
            for (int k = 0; k <= l; ++k) {
                for (int e = 0; e < 3; ++e) {
                    // cout << i << ' ' << j << ' ' << k << ' ' << e << '\n';
                    if (i + j - e > n || k < (2 * j - e) * (heights[i] - heights[i - 1]) || (i < n && j == 1 && e == 2)) continue;
                    // cout << "if\n";
                    int newTot = k - (2 * j - e) * (heights[i] - heights[i - 1]);

                    // case 1: adding new building as new segment not at edge
                    dp[i][j][k][e] += dp[i - 1][j - 1][newTot][e];
                    // cout << "case 1\n";

                    // case 2: adding new building as new segment at edge
                    if (e) dp[i][j][k][e] += (3 - e) * dp[i - 1][j - 1][newTot][e - 1];
                    // cout << "case 2\n";

                    // case 3: adding new building onto segment, not merging segments, not onto edge
                    dp[i][j][k][e] += (2 * j - e) * dp[i - 1][j][newTot][e];
                    // cout << "case 3\n";

                    // case 4: adding new building onto segment, at edge
                    if (e == 1) dp[i][j][k][e] += 2 * j * dp[i - 1][j][newTot][e - 1];
                    else if (e == 2) {
                        if (j == 1) dp[i][j][k][e] += dp[i - 1][j][newTot][e - 1];
                        else dp[i][j][k][e] += (j - 1) * dp[i - 1][j][newTot][e - 1];
                    }
                    // cout << "case 4\n";

                    // case 5: adding new building onto segment, merging two
                    if (j < n) {
                        if (e == 0) dp[i][j][k][e] += j * (j + 1) * dp[i - 1][j + 1][newTot][e];
                        else if (e == 1) dp[i][j][k][e] += j * j * dp[i - 1][j + 1][newTot][e];
                        else if (j == 1) dp[i][j][k][e] += dp[i - 1][j + 1][newTot][e];
                        else dp[i][j][k][e] += j * (j - 1) * dp[i - 1][j + 1][newTot][e];
                    }
                    // cout << "case 5\n";

                    dp[i][j][k][e] %= 1'000'000'007;
                    // cout << i << ' ' << j << ' ' << k << ' ' << e << ' ' << dp[i][j][k][e] << '\n';
                }
            }
        }
    }

    int res = 0;
    for (int i = 0; i <= l; ++i) {
        res += dp[n][1][i][2];
        res %= 1'000'000'007;
    }

    cout << res << '\n';

    // srand(time({}));

    // int n = 1;
    // for (int i = 0; i < 1000; ++i) {
    //     vector<int> heights;
    //     vector<bool> inHeights(1001, false);
    //     while (heights.size() < n) {
    //         int val = rand() % 1000 + 1;
    //         if (inHeights[val]) continue;
    //         inHeights[val] = true;
    //         heights.push_back(val);
    //     }
    //     sort(heights.begin(), heights.end());
    //     cout << "Test " << i + 1 << ": \n";
    //     for (int &j : heights) cout << j << ' ';
    //     cout << '\n';
    //     for (int l = 0; l <= 1000; l += rand() % 100 + 1) {
    //         // cout << "l: " << l << '\n';
    //         int codeVal = code(n, l, heights);
    //         // cout << "CodeVal: " << codeVal << '\n';
    //         // int bruteforceVal = bruteforce(n, l, heights);
    //         // cout << "BruteforceVal: " << bruteforceVal << '\n';
    //         // if (codeVal != bruteforceVal) {
    //         //     cout << "Error\n";
    //         //     return 0;
    //         // }
    //     }
    // }

    // vector<int> heights = {6, 7, 8, 9};
    // cout << code(4, 4, heights) << '\n';

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