P2261 [CQOI2007]余数求和
首先这是一道整除分块的题
关于整除分块可以参考整除分块(数论分块)。
这道题给了n和k两个整数,但是我们要求的是k%i。由于没有给出n与k的相对大小,我们需要分情况来进行判断。
首先,如果n>=k
我们要先计算i∈[1, n]的情况,这时要采用数论分块,并由他们的整除的值相同来推出这一个区间的公式。
k
%
i
=
k
−
⌊
k
i
⌋
i
r
e
s
=
(
r
−
l
+
1
)
k
−
⌊
k
i
⌋
(
∑
i
=
l
r
i
)
r
e
s
=
(
r
−
l
+
1
)
k
−
(
r
+
l
)
(
r
−
l
+
1
)
⌊
k
l
⌋
/
2
k \% i = k - \lfloor\frac{k}{i}\rfloor i \\ res = (r - l + 1) k - \lfloor\frac{k}{i}\rfloor(\sum_{i = l}^ri) \\ res = (r - l + 1) k - (r + l)(r - l + 1)\lfloor\frac{k}{l}\rfloor/2
k%i=k−⌊ik⌋ires=(r−l+1)k−⌊ik⌋(i=l∑ri)res=(r−l+1)k−(r+l)(r−l+1)⌊lk⌋/2
分别计算每一个区块,最后i大于k的部分k%i的值一定是k,单独加上即可
当k > n时,要注意r的最大值为n,每一次求r的时候需要单独判断一下。
C++
#include <iostream>
using namespace std;
typedef long long ll;
int main()
{
ll n, k;
cin >> n >> k;
ll res = 0;
if (n >= k)
{
for (ll l = 1, r; l <= k; l = r + 1)
{
r = k / (k / l);
res += (r - l + 1) * k - (r + l) * (r - l + 1) * (k / l) / 2;
}
res += (n - k) * k;
}
else
{
for (ll l = 1, r; l <= n; l = r + 1)
{
r = min(n, k / (k / l));
res += (r - l + 1) * k - (r + l) * (r - l + 1) * (k / l) / 2;
}
}
cout << res << endl;
return 0;
}