Skip to content

Floor Sum

Returns the sum

\[ \sum_{i=0}^{n-1} \Bigl\lfloor \frac{a\times i + b}{m} \Bigr\rfloor \]

in \(O(\log m)\) complexity.

Code

My implementation was stolen straight from AtCoder Library.

Floor Sum
// Floor Sum {{{
// sum of floor[i=0...n-1]((a*i+b)/m)
unsigned long long __floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
  unsigned long long ans = 0;
  while (true) {
    if (a >= m) {
      ans += n * (n - 1) / 2 * (a / m);
      a %= m;
    }
    if (b >= m) {
      ans += n * (b / m);
      b %= m;
    }

    unsigned long long y_max = a * n + b;
    if (y_max < m) break;
    // y_max < m * (n + 1)
    // floor(y_max / m) <= n
    n = (unsigned long long)(y_max / m);
    b = (unsigned long long)(y_max % m);
    swap(m, a);
  }
  return ans;
}

long long floor_sum(long long n, long long m, long long a, long long b) {
  unsigned long long ans = 0;
  if (a < 0) {
    unsigned long long a2 = (a%m+m)%m;
    ans -= 1ULL * n * (n - 1) / 2 * ((a2 - a) / m);
    a = a2;
  }
  if (b < 0) {
    unsigned long long b2 = (a%m+m)%m;
    ans -= 1ULL * n * ((b2 - b) / m);
    b = b2;
  }
  return ans + __floor_sum_unsigned(n, m, a, b);
}
//}}}