前言
上去一眼,感觉就是傻逼题,整除分块搞一下,复杂度也就sqrt(1)+sqrt(2)+…+sqrt(1e5) (没有仔细去算这个值是多少),感觉上大分了。。
然后疯狂TLE test44
后面算了一下上面那个式子,复杂度大概2e7,但是因为过程中还有反复的取模操作,所以稳稳的TLE了。。
思路
其实可以根据素数筛法来优化这个计算过程,我们计算一个数是不是素数,其实就是枚举sqrt以内的看能不能整除,这样子复杂度自然高,而素数筛则是反过来,我去枚举因子筛掉那些能整除的数。
同理,整除分块是枚举这个值,看有多少个答案能被计算进去,那么根据素数筛的提示,我们反过来,去考虑这些所谓的答案能对哪些数字有贡献,那么答案就呼之欲出了
类似素数筛的过程,枚举给定数组中的一个数字x,然后计算区间
[x,2x)这个区间数字的个数,这个区间内的每个数字贡献答案为1
[2x,3x)这个区间数字的个数,这个区间内每个数字贡献答案为2
…
注意如果有多少个x的话,需要乘上x个个数,因为一个x就贡献了那么多,区间中的个数,数组标记,扫个前缀和即可。
typedef long long ll;
const ll mod=1e9+7;
class Solution {
public:
int sumOfFlooredPairs(vector<int>& nums) {
vector<int>cnt(100001,0);
//数组标记
for(auto &x:nums){
cnt[x]++;
}
//扫个前缀和
for(int i=1;i<=100000;i++){
cnt[i]+=cnt[i-1];
}
ll ans=0;
for(int i=1;i<=100000;i++){
//看i这个数字有没有
if(cnt[i]-cnt[i-1]){
//K表示数字i的个数
int K=cnt[i]-cnt[i-1];
//j就是贡献的答案,注意不要数组越界
for(int j=1;i*j<=100000;j++){
ans+=(cnt[min(100000,j*i+i-1)]-cnt[j*i-1])*j%mod*K%mod;
ans%=mod;
}
}
}
return ans;
}
};