题意
(1,k)为一个元组
如果(n,k)是元组的话,那么(n+k,k)和(nk,k)也是元组。
思路
由于元组性质,如果(n,k)为元组,那么一定能够把n除k或减k到1。
故n=n’k+1或者n=n’k
即n%k=0或者n%k=1。
即为计算
∑
i
=
1
k
⌊
N
i
⌋
+
∑
i
=
2
k
⌊
N
−
1
i
⌋
+
k
−
1
\sum_{i=1}^{k}\left \lfloor \frac{N}{i} \right \rfloor+\sum_{i=2}^{k}\left \lfloor \frac{N-1}{i} \right \rfloor+k-1
∑i=1k⌊iN⌋+∑i=2k⌊iN−1⌋+k−1
注意:
因为k=1时N%k都为0,所以会被计算在第一项中,第二项就不需要再枚举k=1了。
被第一项和第二项计算到的元组的n等于n’k+1或者n’k,n’>=1,所以并未计算n=1的元组,由于k=1特殊,已经被第一项包括了,所以答案需要再加上k-1。
关于分块O(
n
\sqrt{n}
n)计算
∑
i
=
1
k
⌊
N
i
⌋
\sum_{i=1}^{k}\left \lfloor \frac{N}{i} \right \rfloor
∑i=1k⌊iN⌋,参考大佬博客
里面有结论。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int main(){
ll n,k,ans=0;
cin>>n>>k;
for(ll l=1,r,p;l<=min(n,k);l=r+1){
p=n/l;
r=min(k,n/p);
ans=(ans+(r-l+1)%mod*p%mod)%mod;
}
n--;
for(ll l=2,r,p;l<=min(n,k);l=r+1){
p=n/l;
r=min(k,n/p);
ans=(ans+(r-l+1)%mod*p%mod)%mod;
}
ans=(ans+k-1)%mod;
printf("%lld\n",ans);
}