1+1/2+1/3+1/4…1/n = log n

Jimmy (xiaoke) Shen
3 min readMay 15, 2021

--

Problem

We have a nice problem today (May 15) on leetcode biweekly contest. It needs us to know the fact of

1+1/2+1/3+1/4…1/n = log n

1862. Sum of Floored Pairs

Explanation

Suppose we have the nums in sorted order.

[x1, x2, x3, …]

For each x, traverse the j from 1 to n to find the numbers in the following region

[x*j, x*(j+1))

In order to counter how many number in the region of [a, b), we can use a prefix frequency sum to computer the result in O(1).

We also need consider the special case of same numbers such as

[7, 7, 7, 7]

In this case, the result is Len(nums)*(Len(nums)-1) based on the multiplication rule.

Complexity

[x1, x2, x3, …MX]

Where MX is the maximum value as we sort the nums first.

Let’s think about the special case of ,

[1, 2, 3, 4, 5, 6]

For

  • x = 1, j can be 1, 2, 3, … 6 which is 6
  • x = 2, j can be 1, 2, 3 , which is 6/2
  • x = 3, j can be 1, 2, which is 6/3
  • x = 4, j can be 1, which is 6/4

In a general case, j are from

n, n/2, n/3, …

sum(n, n/2, n/3, …) = n*(sum(1, 1/2, 1/3, …1/n)) = n log n

See this article to find how to compute sum(1, 1/2, 1/3, …1/n)

So the complexity is O(n log n)

Code

// set N as two times larger to get rid of out of boundary issue
const int N = 200010;
int cnt[N];
const int mod = 1e9 + 7;
class Solution {
public:
int sumOfFlooredPairs(vector<int>& a) {
const int n = a.size();
memset(cnt, 0, sizeof cnt);
long long ret = 0, thisret = 0;
for (auto &x:a) cnt[x]++;
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
const int m = a.size();
int mx = a.back();
vector<int> prefixsum(N, n);
prefixsum[0] = 0;
for (int i = 1; i <=mx; ++i) {
prefixsum[i] = prefixsum[i-1] + cnt[i];
}
for (auto &x: a) {
// for the same number such as [7, 7, 7, 7]
ret += cnt[x]*(cnt[x] - 1);
int lower, upper;
for (int j = 1; x*j <= mx; ++j) {
lower = x*j;
upper = x*(j+1) - 1;
if(j == 1) ret += (long long)cnt[x]*j*(prefixsum[upper] - prefixsum[lower]);
else ret += (long long)cnt[x]*j*(prefixsum[upper] - prefixsum[lower - 1]);
}
}
// for the num itself
ret += n;
return ret % mod;
}
};

A more concised code adjusted from [1]

typedef long long LL;
const int N = 100010, MOD = 1e9 + 7;
int s[N];
class Solution {
public:
int sumOfFlooredPairs(vector<int>& nums) {
memset(s, 0, sizeof s);
// get the count for nums
for (auto &x : nums) s[x]++;
// compute prefix frequency inplace
for (int i = 1; i < N; ++i) s[i] += s[i-1];
int ret = 0;
for (int i = 1; i < N; ++i)
for (int j = 1; i*j < N; ++j)
{
int l = i * j, r = min(N -1, i * (j + 1) - 1);
// s[i] - s[i-1] is the count of i
ret += (s[i] - s[i-1])*j*(s[r] - s[l-1]);
ret %= MOD;
}
return ret;
}
};

Reference

[1] https://www.acwing.com/activity/content/code/content/1239353/

--

--