这是一道老题,但是作为一道省选题,它的代码却短小精悍,可以观赏。
我们只需要进行数学推导即可解决。(60分暴力分应该是可以秒拿的)
由题意得:
a
n
s
=
∑
i
=
1
n
k
%
i
ans=\sum\limits_{i=1}^{n}k\%i
ans=i=1∑nk%i
首先我们需要知道
a
%
b
a\%b
a%b 可以表示为
a
−
b
∗
⌊
a
b
⌋
a-b*\lfloor\frac{a}{b}\rfloor
a−b∗⌊ba⌋这个应该是在代码中经常用到的
所以
a
n
s
=
∑
i
=
1
n
k
−
i
∗
⌊
k
i
⌋
=
n
∗
k
−
∑
i
=
1
n
i
∗
⌊
k
i
⌋
ans=\sum\limits_{i=1}^{n}k-i*\lfloor\frac{k}{i}\rfloor=n*k-\sum\limits_{i=1}^{n}i*\lfloor\frac{k}{i}\rfloor
ans=i=1∑nk−i∗⌊ik⌋=n∗k−i=1∑ni∗⌊ik⌋
然后
⌊
k
i
⌋
\lfloor\frac{k}{i}\rfloor
⌊ik⌋ 可以分块来做,
⌊
k
i
⌋
\lfloor\frac{k}{i}\rfloor
⌊ik⌋大约有
k
\sqrt k
k种取值,所以时间复杂度
O
(
k
)
O(\sqrt k)
O(k)
所以代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,k;
int main(){
scanf("%lld%lld",&n,&k);
long long ans=n*k;
for(long long l=1,r;l<=n;l=r+1) {
if(k/l!=0) r=min(k/(k/l),n);
else r=n;
ans-=(k/l)*(r-l+1)*(l+r)/2;
}
printf("%lld",ans);
return 0;
}