CSES - Coding Company

Authors: Benjamin Qi, Andi Qu, Daniel Zhu


First, sort the people. This allows us to express the contribution of each team as (Skill of last person)(Skill of first person)(\text{Skill of last person}) - (\text{Skill of first person}). Let sis_i denote the skill of the ii-th person.

dp[i][j][k]=dp[i][j][k] = The number of ways we can form teams from the first ii people such that there are jj "unfinished" teams and the total penalty so far is kk. If the ll-th person is the least skilled in an unfinished team, we define its contribution to the penalty as sl-s_l. Similarly, finishing a team with person rr contributes srs_r to the penalty. These definitions follow directly from the previous observation that the contribution of a team is srsls_r - s_l.

There are 4 cases when we transition from i1i - 1 to ii:

  • We make a team consisting of only person ii.
    • dp[i1][j][k]dp[i - 1][j][k] transitions to the state dp[i][j][k]dp[i][j][k] (unfinished teams and penalty are not affected).
  • We append person ii to an unfinished team.
    • This transitions to the state dp[i][j][k]dp[i][j][k] (again, unfinished teams and penalty are not affected). There are jj unfinished teams we can choose to extend, so dp[i][j][k]+=jdp[i1][j][k]dp[i][j][k] \mathrel{+}= j \cdot dp[i - 1][j][k].
  • We use person ii to "finish" an unfinished team.
    • This transitions to the state dp[i][j1][k+si]dp[i][j - 1][k + s_i] (one less unfinished team, and we add to penalty as discussed above). There are again jj unfinished teams to choose from, so dp[i][j1][k+s[i]]+=jdp[i1][j][k]dp[i][j - 1][k + s[i]] \mathrel{+}= j \cdot dp[i - 1][j][k].
  • We start a new unfinished team with person ii.
    • This transitions to the state dp[i][j+1][ks[i]]dp[i][j + 1][k - s[i]] (one more unfinished team, and we subtract from penalty as discussed above).

Two more things:

  • kk in our DP array can be negative, so just add 5000 to each kk; there can be at most N/2=50N/2 = 50 unfinished intervals, and each of them contributes at most 100-100.
  • dp[i]dp[i] depends only on dp[i1]dp[i - 1], so we can drop the first dimension that we store (to save memory).

I believe that this is called the "open and close interval trick". See zscoder's blog post for more information and problems.

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int M = 1e9 + 7;
const int K = 5e3; // K is an offset to account for negatives
int main() {
int n;

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!