Consider a sequence $A = (a_1, a_2, \dots, a_n)$. We want to partition $A$ into contiguous subsequences, and then arrange these subsequences to form a new sequence $f_1, f_2, \dots, f_k$. Each contiguous subsequence $f_1, \dots, f_p$ must satisfy either $f_1 \le f_2 \le \dots \le f_p$ or $f_1 \ge f_2 \ge \dots \ge f_p$. The cost associated with such a subsequence is $f_p - f_1 + f_p - f_k$ if it is of the form $f_1 \le \dots \le f_p \ge \dots \ge f_k$. We are looking for a partition that minimizes the total cost.
This problem can be approached using dynamic programming. Let's sort the original sequence $A$ in descending order. We can define a DP state $dp_{i, j, k, x, y}$ representing the number of ways to partition the first $i$ elements of the sorted sequence into $j$ contiguous subsequences, with a total cost of $k$. The states $x$ and $y$ are booleans indicating whether the first and last elements of the entire constructed sequence have been determined, respectively.
The transitions involve considering how to place the $i$-th element $A_i$:
-
Start a new subsequence: If $A_i$ starts a new subsequence, the number of subsequences increases by one. The cost increases by $2A_i$ if this new subsequence is not the first or last of the entire sequence. If it's the first element, the cost increases by $A_i$; if it's the last, the cost increases by $A_i$. The number of ways to do this is multiplied by $(j+1-x-y)$, representing the number of available endpoints (either existing subsequence ends or the start/end of the entire sequence).
- $dp_{i, j+1, k + 2A_i, x, y} ext{ (if } A_i ext{ is neither start nor end)}$
- $dp_{i, j+1, k + A_i, 1, y} ext{ (if } A_i ext{ is the start)}$
- $dp_{i, j+1, k + A_i, x, 1} ext{ (if } A_i ext{ is the end)}$
-
Extend an existing subsequence: If $A_i$ extends an existing subsequence (either at the beginning or end), the number of subsequences remains the same. The cost increases by $A_i - A_{i+1}$ for each subsequence whose start or end needs to be updated. The number of ways to do this is multiplied by $(2j - x - y)$, representing the number of available ends of the $j$ subsequences.
- $dp_{i, j, k + (2j - x - y)(A_i - A_{i+1}), x, y} ext{ (general case)}$
- $dp_{i, j, k + (2j - 1 - y)(A_i - A_{i+1}), 1, y} ext{ (if } A_i ext{ becomes the new start)}$
- $dp_{i, j, k + (2j - x - 1)(A_i - A_{i+1}), x, 1} ext{ (if } A_i ext{ becomes the new end)}$
-
Merge two subsequences: If $A_i$ merges two adjacent subsequences, the number of subsequences decreases by one. The cost decreases by $2A_i$. This is possible only if there are atleast two subsequences ($j > 1$). The number of ways to do this is multiplied by $(j-1)$.
- $dp_{i, j-1, k - 2A_i, x, y} ext{ (general case)}$
Handling the large cost dimension: The dimension $k$ for cost can be very large, making the DP infeasible. We can use a differencing technique. Instead of directly storing the total cost, we can store the incremental cost. When adding $A_i$, the cost increase for subsequences that need to append $A_i$ is $(j - x - y)(A_i - A_{i+1})$. This formulation allows us to avoid the large cost dimension by focusing on the differences between adjacent sorted elements.
DP State Refinement: Let $dp[i][j][x][y]$ be the number of ways to partition the first $i$ elements into $j$ segments, where $x$ indicates if the first element of the overall sequence is fixed (0 or 1), and $y$ indicates if the last element of the overall sequence is fixed (0 or 1). The cost will be implicitly managed by the transitions.
For the transition when considering $A_i$ and $A_{i+1}$:
-
Adding $A_i$ as a new segment:
- If $A_i$ is neither the first nor last of the overall sequence: $dp[i+1][j+1][x][y] += dp[i][j][x][y] imes (j+1-x-y)$.
- If $A_i$ becomes the first element: $dp[i+1][j+1][1][y] += dp[i][j][0][y] imes (j+1-0-y)$.
- If $A_i$ becomes the last element: $dp[i+1][j+1][x][1] += dp[i][j][x][0] imes (j+1-x-0)$.
-
Adding $A_i$ to an existing segment (as the new start or end):
- $dp[i+1][j][x][y] += dp[i][j][x][y] imes (2j-x-y)$.
- If $A_i$ becomes the new start: $dp[i+1][j][1][y] += dp[i][j][0][y] imes (2j-0-y)$.
- If $A_i$ becomes the new end: $dp[i+1][j][x][1] += dp[i][j][x][0] imes (2j-x-0)$.
-
Merging two segments with $A_i$:
- $dp[i+1][j-1][x][y] += dp[i][j][x][y] imes (j-1)$.
The cost calculation: The cost update can be seen as adding $(j-x-y) imes (A_i - A_{i+1})$ to the total cost when $A_i$ is processed, and then $A_{i+1}$ is processed. This way, the cost is accumulated based on the difference of consecutive sorted elements.
The DP state would be dp[i][j][x][y], where i is the number of elements processed, j is the number of segments, x is whether the first element is fixed, and y is whether the last element is fixed. The base case is $dp[0][0][0][0] = 1$.
After computing the DP for all $n$ elements, the final answer is $\sum_{i=0}^L dp[n][1][1][1]$, where $L$ is the maximum possible cost. However, due to the differencing approach, we effectively sum up the contributions. The state should be dp[segments][is_first_fixed][is_last_fixed], and we iterate through elements. The cost is accumulated implicitly. The transitions should reflect the cost change: dp[j+1][k+(2*(j+1)-x-y)*(a[i]-a[i+1])][x][y]. Note that a[i+1] is used for the difference calculation.
Let $dp[i][j][x][y]$ be the number of ways to partition the first $i$ elements into $j$ segments, with $x$ (0/1) indicating if the first element is fixed, and $y$ (0/1) indicating if the last element is fixed. The cost difference $A_i - A_{i+1}$ is applied at each step. The initial state is $dp[0][0][0][0] = 1$. When considering $A_i$:
-
Add $A_i$ as a new segment:
- $dp[i][j+1][x][y] extbf{ += } dp[i-1][j][x][y] imes (j+1-x-y)$.
- $dp[i][j+1][1][y] extbf{ += } dp[i-1][j][0][y] imes (j+1-0-y)$ (if $A_i$ is start).
- $dp[i][j+1][x][1] extbf{ += } dp[i-1][j][x][0] imes (j+1-x-0)$ (if $A_i$ is end).
-
Add $A_i$ to an existing segment:
- $dp[i][j][x][y] extbf{ += } dp[i-1][j][x][y] imes (2j-x-y)$.
- $dp[i][j][1][y] extbf{ += } dp[i-1][j][0][y] imes (2j-0-y)$ (if $A_i$ is start).
- $dp[i][j][x][1] extbf{ += } dp[i-1][j][x][0] imes (2j-x-0)$ (if $A_i$ is end).
-
Merge two segments:
- $dp[i][j-1][x][y] extbf{ += } dp[i-1][j][x][y] imes (j-1)$.
Cost Accumulation: The cost is accumulated by $dp[ ext{current_segments}][ ext{cost} + (j-x-y) imes (A_i - A_{i+1})][x][y]$. The maximum cost considered is $L$. The DP state should be $dp[i][ ext{segments}][ ext{cost}][ ext{is_first_fixed}][ ext{is_last_fixed}]$. Since the cost dimension is too large, we use the differencing technique.
Let $dp[i][j][x][y]$ be the number of ways using first $i$ elements, forming $j$ segments, with $x$ indicating if the first element is fixed, and $y$ indicating if the last element is fixed. The cost is implicitly handled by the transition value $A_i - A_{i+1}$.
The state should be dp[num_elements][num_segments][is_first_fixed][is_last_fixed]. The transitions accumulate the cost based on the difference $A_i - A_{i+1}$.
The final answer is $\sum dp[n][1][1][1]$.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MOD = 1e9 + 7;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
long long L;
cin >> n >> L;
vector<long long> a(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
sort(a.begin() + 1, a.end(), greater<long long>());
if (n == 1) {
cout << 1 << endl;
return 0;
}
// dp[i][j][x][y] = number of ways using first i elements, j segments, x=is_first_fixed, y=is_last_fixed
// The cost is implicitly handled by the difference of consecutive sorted elements.
// The maximum cost considered is L.
vector<vector<vector<vector<vector<long long>>>>> dp(2, vector<vector<vector<vector<long long>>>>(n + 1, vector<vector<vector<long long>>>(n + 1, vector<vector<long long>>(2, vector<long long>(2, 0)))));
int pre = 0, cur = 1;
dp[pre][0][0][0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= i; ++j) {
for (int k = 0; k <= L; ++k) {
for (int x = 0; x < 2; ++x) {
for (int y = 0; y < 2; ++y) {
dp[cur][j][k][x][y] = 0;
}
}
}
}
long long diff = (i == n) ? 0 : (a[i] - a[i+1]); // Use a[i+1] for difference calculation
for (int j = 0; j < i; ++j) {
for (int k = 0; k <= L; ++k) {
for (int x = 0; x < 2; ++x) {
for (int y = 0; y < 2; ++y) {
if (dp[pre][j][k][x][y] == 0) continue;
// Case 1: Add a[i] as a new segment
// 1a: Not first or last overall
if (j + 1 <= n) {
long long cost_increase = (long long)(j + 1 - x - y) * diff;
if (k + cost_increase <= L) {
dp[cur][j + 1][k + cost_increase][x][y] = (dp[cur][j + 1][k + cost_increase][x][y] + dp[pre][j][k][x][y]) % MOD;
}
}
// 1b: Becomes the first overall
if (j + 1 <= n && x == 0) {
long long cost_increase = (long long)(j + 1 - 0 - y) * diff;
if (k + cost_increase <= L) {
dp[cur][j + 1][k + cost_increase][1][y] = (dp[cur][j + 1][k + cost_increase][1][y] + dp[pre][j][k][0][y]) % MOD;
}
}
// 1c: Becomes the last overall
if (j + 1 <= n && y == 0) {
long long cost_increase = (long long)(j + 1 - x - 0) * diff;
if (k + cost_increase <= L) {
dp[cur][j + 1][k + cost_increase][x][1] = (dp[cur][j + 1][k + cost_increase][x][1] + dp[pre][j][k][x][0]) % MOD;
}
}
// Case 2: Add a[i] to an existing segment
if (j > 0) {
long long cost_increase = (long long)(2 * j - x - y) * diff;
if (k + cost_increase <= L) {
dp[cur][j][k + cost_increase][x][y] = (dp[cur][j][k + cost_increase][x][y] + dp[pre][j][k][x][y]) % MOD;
}
}
// 2b: Becomes the first overall
if (j > 0 && x == 0) {
long long cost_increase = (long long)(2 * j - 0 - y) * diff;
if (k + cost_increase <= L) {
dp[cur][j][k + cost_increase][1][y] = (dp[cur][j][k + cost_increase][1][y] + dp[pre][j][k][0][y]) % MOD;
}
}
// 2c: Becomes the last overall
if (j > 0 && y == 0) {
long long cost_increase = (long long)(2 * j - x - 0) * diff;
if (k + cost_increase <= L) {
dp[cur][j][k + cost_increase][x][1] = (dp[cur][j][k + cost_increase][x][1] + dp[pre][j][k][x][0]) % MOD;
}
}
// Case 3: Merge two segments
if (j > 1) {
long long cost_decrease = -2 * diff;
if (k + cost_decrease >= 0) {
dp[cur][j - 1][k + cost_decrease][x][y] = (dp[cur][j - 1][k + cost_decrease][x][y] + dp[pre][j][k][x][y] * (j - 1)) % MOD;
}
}
}
}
}
}
swap(pre, cur);
}
long long ans = 0;
for (int k = 0; k <= L; ++k) {
ans = (ans + dp[pre][1][k][1][1]) % MOD;
}
cout << ans << endl;
return 0;
}