余数之和
题目链接
这道题目让我们求这样一个函数的值:F(n) = (n % 1) + (n % 2) + (n % 3) + … (n % n)
由于数据太大,直接暴力做会超时。因此,可以想办法将表达式进行转化:
∑ i = 1 n ( n % i ) = ∑ i = 1 n ( n − i ∗ ⌊ n i ⌋ ) = n ∗ n − ∑ i = 1 n i ∗ ⌊ n i ⌋ \sum_{i=1}^n(n\%i)=\sum_{i=1}^n(n-i*\lfloor\frac ni\rfloor)=n*n-\sum_{i=1}^ni*\lfloor\frac ni\rfloor ∑i=1n(n%i)=∑i=1n(n−i∗⌊in⌋)=n∗n−∑i=1ni∗⌊in⌋
我们容易发现最后转化的式子中,有我们比较熟悉的表达式 ⌊ n i ⌋ \lfloor\frac ni\rfloor ⌊in⌋,因此,我们可以使用数论分块进行处理。这样再使用等差数列求和公式,就能求出求和表达式的值。
由于这道题目数据很大,会爆long long,因此要注意取模。
注意:在等差数列求和公式中,需要除以2,我在做题当中直接除以2,wa了好几次,因此这里改成了乘2的逆元。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int main()
{
ll n;
cin >> n;
ll ans = (n % mod) * (n % mod) % mod;
for (ll l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
if (r > n) r = n;
ll pre = (n / l) % mod * ((r - l + 1) % mod) % mod, pr = (pre * ((r + l) % mod)) % mod;
ans = ((ans - pr * (ll)500000004 % mod) % mod + mod) % mod;
}
cout << ans << endl;
return 0;
}