Blog/USACO Sleeping in Class
profile picture
Yash Singh
USACO Sleeping in Class

USACO Sleeping in Class

In this blog post I'll go over the USACO Sleeping in Class Bronze February 2022 Problem 1 using other resources and solutions.

Statement

We are given an array of integers and have to make all the integers in the array the same in a series of operations. Each operation involves combining two adjacent integers so that a new integer takes their space with their sum. You have to find the minimum number of operations it takes to do so.

Solution

There are two key observations to make here. 1. Each operation subtracts the total number of elements by one. We operate on two elements and end up with one less. 2. The smaller the number we are adding up to, the less the number of operations.

Another way to think of the elements being added is dividing the array into segments. For example, if we have [1,2,3,1,1,1], we can divide the array into [1,2] [3] [1,1,1]. Since we have three segments, that will turn into one integer each in the end, we can get the number of operations with nsn - s where nn is the number of elements and ss is the number of segments. This is because we lose one integer in each operation, and the number of integers we want in the end is ss, so the number of integers we lose are the remaining, nsn - s.

So we have to divide an array of nn number of integers into segments with the amount 1..n1..n. For each segment count, we can have a counter that iterates through each array and makes sure that we reach total_sums\frac{total\_sum}s (target sum for each segment) each time. We can iterate from nn to 11 for ss (larger number better because nsn - s smaller which means less operations) and if the total_sumtotal\_sum is divisible by ss we can do our counter algorithm.

The time complexity for this would be O(n×# of factors of total_sum)\mathcal{O}(n\times\text{\# of factors of total\_sum}). We know that the total sum is 106\le10^6, so we can write up a quick program that will tell the max number of factors given an input:

#include <bits/stdc++.h>
 
using namespace std;
 
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
 
  long long n;
  cin >> n;
 
  long long total[n + 5];
  for (long long i{0}; i <= n; ++i) {
    total[i] = 0;
  }
 
  // Iterate over multiples of each number from 1 -> n / 2
  for (long long i{1}; i <= n / 2; ++i) {
    for (long long j{i}; j <= n; j += i) {
      ++total[j];
    }
  }
 
  // Find the max
  long long mx{-1};
  for (long long i{0}; i <= n; ++i) {
    mx = max(mx, total[i]);
  }
  cout << mx;
  return 0;
}

If we try out 10000001000000 on this, we should get a number around 240240. That is around 2.4×1062.4\times10^6 operations which is well underneath the time limit of 2×1072\times10^7 (max 1010 test cases) for C++.

Implementation

Let's go through an implementation in C++:

#include <bits/stdc++.h>
 
using namespace std;
 
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  int t;
  cin >> t;
  // For each test case
  while (t--) {
    int n;
    cin >> n;
    int a[n];
    // sum
    int sm{0};
    // read in sum and array
    for (int i{0}; i < n; ++i) {
      cin >> a[i];
      sm += a[i];
    }
    // Iterate from n -> 1
    for (int i{n}; i > 0; --i) {
      // If dividing into i segments is feasible
      if (sm % i == 0) {
        // current sum
        int cur = 0;
        // target sum
        int tar = sm / i;
        bool g{1};
        for (int j{0}; j < n; ++j) {
          cur += a[j];
          // can't fit target sum in a segment here
          if (cur > tar) {
            g = 0;
            break;
          }
          // start a new segment
          if (cur == tar) {
            cur = 0;
          }
        }
        // n - i operations taken
        if (g) {
          cout << n - i << endl;
          break;
        }
      }
    }
  }
 
  return 0;
}

Lessons Learnt

A lesson learned in this problem is to make sure you test solutions time complexity properly. In this example we wrote a mini program to give us the maximum number of divisors. Another lesson to take from this problem is to again, divide the input into categories. Dividing up your input is often the key solution to many problems. If you are stuck, look for a way you can categorize or divide up your input so it can be easier to understand.