CSES - Coding Company

Authors: Benjamin Qi, Andi Qu

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.

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

  • We make a team consisting of only person ii.
    • The number of ways to do this is dp[i1][j][k]dp[i - 1][j][k], since the penalty from this team is 0.
  • We append person ii to an unfinished team.
    • The number of ways to do this is jdp[i1][j][k]j \cdot dp[i - 1][j][k], since there are jj teams we can choose from and the penalties don't change.
  • We use person ii to "finish" an unfinished team.
    • The number of ways to do this is (j+1)dp[i1][j+1][ksi](j+1) \cdot dp[i - 1][j + 1][k - s_i], since person ii contributes sis_i to the cost and there were j+1j + 1 teams to choose from.
  • We start a new unfinished team with person ii.
    • The number of ways to do this is dp[i1][j1][k+si]dp[i - 1][j - 1][k + s_i], since person ii contributes si-s_i to the cost.

Two more things:

  • kk in our DP array can be negative, so just add 5000 to each kk.
  • 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 "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;
using ld = long double;
using db = double;
using str = string; // yay python!
using pi = pair<int,int>;
using pl = pair<ll,ll>;

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!