Skip to Content

Skyscraper

Complejidad temporal: O(N2L)\mathcal O(N^2L).

Usaremos DP de componentes conexas  para resolver este problema.

Primero, ordenamos los edificios por altura. Ahora los “insertaremos” en la permutación final en distintas posiciones y contaremos el número de formas de hacerlo.

Sea dp[i][j][k][m]dp[i][j][k][m] el número de formas de insertar los primeros ii edificios en la permutación tales que:

  • Hubo jj “componentes conexas” (es decir, subarreglos con todas las posiciones ocupadas).
  • El “costo total” (suponiendo que todas las posiciones vacías contienen ai+1a_{i + 1}, donde an+1=a_{n + 1} = \infty) es kk.
  • mm de los extremos de la permutación se han ocupado hasta ahora.

Por ejemplo, {?,?,3,?,2,1}\{?, ?, 3, ?, 2, 1\} (una permutación a medio llenar de {1,2,3,4,5,6}\{1, 2, 3, 4, 5, 6\}) se contaría en dp[3][2][5][1]dp[3][2][5][1].

Observemos que no nos importa el orden relativo de las componentes conexas para cada estado de DP. (Imaginemos que son componentes flotantes que podemos sacar del espacio y unir.)

Cuando pasamos de dp[i1]dp[i - 1] a dp[i]dp[i], todas las posiciones vacías cambian de aia_i a ai+1a_{i + 1}, así que el cambio en el costo total (dados jj y mm) sería Δj,m=(2jm)(ai+1ai)\Delta_{j, m} = (2j - m)(a_{i + 1} - a_i). Cada componente conexa contribuye 2(ai+1ai)2(a_{i + 1} - a_i) a Δj,m\Delta_{j, m} salvo las que contienen extremos, que solo contribuyen ai+1aia_{i + 1} - a_i.

Ahora tenemos cinco casos al calcular dp[i][j][k][m]dp[i][j][k][m]:

  • Insertamos aia_i para formar una componente nueva que no contiene un extremo de la permutación.
    • Hubo dp[i1][j1][kΔj,m][m]dp[i - 1][j - 1][k - \Delta_{j, m}][m] formas de hacerlo.
  • Insertamos aia_i para formar una componente nueva que contiene un extremo de la permutación.
    • Solo es posible si m>0m > 0.
    • Si es así, hubo (3m)dp[i1][j1][kΔj,m][m1](3 - m) \cdot dp[i - 1][j - 1][k - \Delta_{j, m}][m - 1] formas de hacerlo.
  • Añadimos aia_i a una componente existente de modo que no contiene un extremo de la permutación.
    • Había 2jm2j - m extremos de componente para elegir, así que hubo (2jm)dp[i1][j][kΔj,m][m](2j - m) \cdot dp[i - 1][j][k - \Delta_{j, m}][m] formas de hacerlo.
  • Añadimos aia_i a una componente existente de modo que contiene un extremo de la permutación.
    • Solo es posible si m>0m > 0.
    • Si m=1m = 1, había 2j2j extremos de componente para elegir, así que hubo 2jdp[i1][j][kΔj,m][m1]2j \cdot dp[i - 1][j][k - \Delta_{j, m}][m - 1] formas de hacerlo.
    • Si m=2m = 2 y j=1j = 1, entonces debe valer i=ni = n, así que hubo dp[i1][j][kΔj,m][m1]dp[i - 1][j][k - \Delta_{j, m}][m - 1] formas de hacerlo.
    • En otro caso, había j1j - 1 extremos de componente para elegir (¡no podemos elegir la otra componente que contiene un extremo de la permutación!), así que hubo (j1)dp[i1][j][kΔj,m][m1](j - 1) \cdot dp[i - 1][j][k - \Delta_{j, m}][m - 1] formas de hacerlo.
  • Insertamos aia_i para unir dos componentes existentes.
    • Si m=2m = 2 e i=ni = n, entonces solo pueden quedar dos componentes, así que hubo dp[i1][j+1][kΔj,m][m]dp[i - 1][j + 1][k - \Delta_{j, m}][m] formas de hacerlo.
    • Si m=2m = 2 en otro caso, había j(j1)j(j - 1) pares ordenados de componentes para elegir, así que hubo j(j1)dp[i1][j+1][kΔj,m][m]j(j - 1) \cdot dp[i - 1][j + 1][k - \Delta_{j, m}][m] formas de hacerlo.
    • Si m=1m = 1, había j2j^2 pares ordenados de componentes para elegir, así que hubo j2dp[i1][j+1][kΔj,m][m]j^2 \cdot dp[i - 1][j + 1][k - \Delta_{j, m}][m] formas de hacerlo.
    • En otro caso, había j(j+1)j(j + 1) pares ordenados de componentes para elegir, así que hubo j(j+1)dp[i1][j+1][kΔj,m][m]j(j + 1) \cdot dp[i - 1][j + 1][k - \Delta_{j, m}][m] formas de hacerlo.
#include <bits/stdc++.h> typedef long long ll; using namespace std; const ll MOD = 1e9 + 7; int a[102]; ll dp[102][102][1002][3]; int main() { ios_base::sync_with_stdio(0); cin.tie(0); int n, l; cin >> n >> l; if (n == 1) return cout << 1, 0; for (int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + n + 1); a[n + 1] = 10000; 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 m = 0; m <= 2; m++) { int cost_diff = (2 * j - m) * (a[i + 1] - a[i]); if (cost_diff > k || i + j + 1 - m > n) continue; // Case 1 dp[i][j][k][m] += dp[i - 1][j - 1][k - cost_diff][m]; // Case 2 if (m) dp[i][j][k][m] += (3 - m) * dp[i - 1][j - 1][k - cost_diff][m - 1]; // Case 3 dp[i][j][k][m] += (2 * j - m) * dp[i - 1][j][k - cost_diff][m]; // Case 4 if (m == 1) dp[i][j][k][m] += 2 * j * dp[i - 1][j][k - cost_diff][m - 1]; if (m == 2) { if (i == n) dp[i][j][k][m] += dp[i - 1][j][k - cost_diff][m - 1]; else if (j > 1) dp[i][j][k][m] += (j - 1) * dp[i - 1][j][k - cost_diff][m - 1]; } // Case 5 if (m == 2) { if (i == n) dp[i][j][k][m] += dp[i - 1][j + 1][k - cost_diff][m]; else dp[i][j][k][m] += j * (j - 1) * dp[i - 1][j + 1][k - cost_diff][m]; } else if (m == 1) dp[i][j][k][m] += j * j * dp[i - 1][j + 1][k - cost_diff][m]; else dp[i][j][k][m] += j * (j + 1) * dp[i - 1][j + 1][k - cost_diff][m]; dp[i][j][k][m] %= MOD; } } } } ll ans = 0; for (int i = 0; i <= l; i++) ans += dp[n][1][i][2]; cout << ans % MOD; return 0; }