1862. 向下取整数对和(暴力,调和级数的复杂度)

给你一个整数数组 nums ,请你返回所有下标对 0 <= i, j < nums.length 的 floor(nums[i] / nums[j]) 结果之和。由于答案可能会很大,请你返回答案对109 + 7 取余 的结果。

函数 floor() 返回输入数字的整数部分。

 

示例 1:

输入:nums = [2,5,9]
输出:10
解释:
floor(2 / 5) = floor(2 / 9) = floor(5 / 9) = 0
floor(2 / 2) = floor(5 / 5) = floor(9 / 9) = 1
floor(5 / 2) = 2
floor(9 / 2) = 4
floor(9 / 5) = 1
我们计算每一个数对商向下取整的结果并求和得到 10 。

示例 2:

输入:nums = [7,7,7,7,7,7,7]
输出:49

 

提示:

  • 1 <= nums.length <= 1e5
  • 1 <= nums[i] <= 1e5
 
 
这个题是只需要枚举他的倍数的,因为对于一个数i,枚举他的倍数j,那么这个倍数是j的数的范围为j*i----(j+1)*x-1,所以我们要想办法统计出来这个范围里面的
数的个数,这个是可以用前缀和来处理的,这里有一个小技巧,我没枚举的时候不能枚举这个序列的数,而是枚举从1到1e5.
下面看这两种写法
写法1:
        for(int i=1;i<maxn;i++){
            for(int j=1;j*i<maxn;j++){
                int l=j*i,r=min(maxn-1,(j+1)*i-1);
                 int s = (ll)(sum[r] - sum[l - 1]) * j % mod;
                ans = (ans + (ll)s * (sum[i] - sum[i - 1])) % mod;//这个数的个数
            }
        }

 

写法2:
ll ans=0;
for(auto x:nums){
     for(int j=1;x*j<maxn;j++){
          int l=j*x,r=min(maxn-1,(j+1)*x-1);
          int s=sum[r]-sum[l-1];//个数
          ans+=(j*s)%mod;
     }
}
我们提交一下会发现写法2是会被T掉的,为什么呢?
举个例子把,就是又1e5个1的话,做法1就会被T掉,而做法2就不会,自己好好想想把,
所以说这个一个小技巧吧,
const int maxn=1e5+100,mod=1e9+7;
typedef long long ll;
int sum[maxn];
class Solution {
public:
    int sumOfFlooredPairs(vector<int>& nums) {
        memset(sum,0,sizeof(sum));
        for(auto x: nums) sum[x]++;
        for(int i=1;i<maxn;i++){
            sum[i]+=sum[i-1];
        }
        ll ans=0;
        for(int i=1;i<maxn;i++){
            for(int j=1;j*i<maxn;j++){
                int l=j*i,r=min(maxn-1,(j+1)*i-1);
                 int s = (ll)(sum[r] - sum[l - 1]) * j % mod;
                ans = (ans + (ll)s * (sum[i] - sum[i - 1])) % mod;
            }
        }
        return ans%mod;
    }
};

 

posted @ 2021-06-19 18:23  lipu123  阅读(226)  评论(0)    收藏  举报