BZOJ 1257 余数之和

时间:2022-03-19 09:58:27

Description

给出正整数\(n\)和\(k\),计算\(j(n, k)=k\;mod\;1\;+\;k\;mod\;2\;+\;k\;mod\;3\;+\;…\;+\;k\;mod\;n\)的值,其中\(k\;mod\;i\)表示\(k\)除以\(i\)的余数。例如\(j(5, 3)=3\;mod\;1\;+\;3\;mod\;2\;+\;3\;mod\;3\;+\;3\;mod\;4\;+\;3\;mod\;5=0+1+0+3+3=7\)

Input

输入仅一行,包含两个整数\(n, k\)。

Output

输出仅一行,即\(j(n, k)\)。

Sample Input

5 3

Sample Output

7

HINT

\(50\%\)的数据满足:\(1 \le n, k le 1000\)。

\(100\%\)的数据满足:\(1 \le n ,k \le 10^{9}\)。

\(n\;mod\;i=n-i \times \lfloor \frac{n}{i} \rfloor\),因此我们可以对\(\lfloor \frac{n}{i} \rfloor\)相同的值的一块进行分块(\(\sqrt{n}\)块)。

#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std; typedef long long ll; inline ll sum(ll a,ll b) { return (a+b)*(b-a+1)>>1; } inline ll calc(ll n,ll m)
{
ll ret = 0;
if (m > n) ret = (m-n)*n,m = n;
ll pos;
for (ll i = 1;i <= m;i = pos+1)
{
pos = min(n/(n/i),m);
ret += (pos-i+1)*n-sum(i,pos)*(n/i);
}
return ret;
} int main()
{
freopen("1257.in","r",stdin);
freopen("1257.out","w",stdout);
ll n,m;
scanf("%lld %lld",&m,&n);
printf("%lld",calc(n,m));
fclose(stdin); fclose(stdout);
return 0;
}