恶心至极!!!!!!!!
题目链接
思路
求 ∑ i = 1 n ( n m o d i ) ∑ j = 1 m ( m m o d j ) [ i ≠ j ] \sum\limits_{i = 1}^{n} (n \mod i)\sum\limits_{j=1}^{m}(m\mod j)[i\neq j] i=1∑n(nmodi)j=1∑m(mmodj)[i=j]
假设没有限制情况 i ≠ j i\neq j i=j
∑ i = 1 n ( n m o d i ) ∑ j = 1 m ( m m o d j ) \sum\limits_{i = 1}^{n} (n \mod i)\sum\limits_{j=1}^{m}(m\mod j) i=1∑n(nmodi)j=1∑m(mmodj)
只看左半部分:
∑ i = 1 n ( n % i ) \ \ \ \sum\limits_{i=1}^{n}(n\% i) i=1∑n(n%i)
= ∑ i = 1 n ( n − ⌊ n i ⌋ ∗ i ) = \sum\limits_{i=1}^{n}(n - \lfloor \frac{n}{i}\rfloor * i) =i=1∑n(n−⌊in⌋∗i)
= ∑ i = 1 n n − ∑ i = 1 n ⌊ n i ⌋ ∗ i = \sum\limits_{i=1}^{n}n - \sum\limits_{i = 1}^{n}\lfloor\frac{n}{i}\rfloor*i =i=1∑nn−i=1∑n⌊in⌋∗i
显然数论分块,右半部分同理,都可以数论分块做(余数求和那道题的完全一样的做法)
再看 i = j i=j i=j的情况,即
$ \sum\limits_{i=1}^{k=\min(n,m)}(n\mod i)(m\mod i)$
= ∑ i = 1 k ( n − ⌊ n i ⌋ ∗ i ) ( m − ⌊ m i ⌋ ∗ i ) =\sum\limits_{i=1}^{k}(n-\lfloor\frac{n}{i}\rfloor*i)(m-\lfloor\frac{m}{i}\rfloor*i) =i=1∑k(n−⌊in⌋∗i)(m−⌊im⌋∗i)
= ∑ i = 1 k ( n m − ( ⌊ n i ⌋ ∗ m + ⌊ m i ⌋ ∗ n ) ∗ i + ⌊ n i ⌋ ∗ ⌊ m i ⌋ ∗ i 2 ) =\sum\limits_{i=1}^{k}(nm-(\lfloor\frac{n}{i}\rfloor*m+\lfloor\frac{m}{i}\rfloor*n)*i+\lfloor\frac{n}{i}\rfloor*\lfloor\frac{m}{i}\rfloor*i^2) =i=1∑k(nm−(⌊in⌋∗m+⌊im⌋∗n)∗i+⌊in⌋∗⌊im⌋∗i2)
用数论分块求出上面两个式子,用总的减去下面这个式子,注意除法要用逆元
p s ps ps:
能模就模,好事多模
小知识点
∑ i = l r i = ( r − l + 1 ) ∗ ( l + r ) / 2 \sum\limits_{i = l}^{r}i=(r -l + 1)*(l + r) / 2 i=l∑ri=(r−l+1)∗(l+r)/2
∑ i = 1 n i 2 = n ∗ ( n + 1 ) ∗ ( 2 ∗ n + 1 ) / 6 \sum\limits_{i = 1} ^{n}i^2= n * (n + 1) * (2* n + 1)/ 6 i=1∑ni2=n∗(n+1)∗(2∗n+1)/6
时间复杂度 O ( n ) O(\sqrt{n}) O(n)
代码
/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int inv6 = 3323403;
const int inv2 = 9970209;
const int mod = 19940417;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, k;
inline int sum(int l, int r) {
return (r - l + 1) * (l + r) / 2 % mod;
}
inline int sum1(int r) {
return r * (r + 1) % mod * (2 * r + 1) % mod * inv6 % mod;
}
inline int sum2(int l, int r) {
return (sum1(r) - sum1(l - 1)) % mod;
}
inline int solve(int n) {
int ans = n * n;
for (int l = 1, r; l <= n; l = r + 1) {
if (n / l == 0) break;
r = min(n / (n / l), n);
ans -= (n / l) % mod * sum(l, r) % mod;
ans %= mod;
}
return (ans % mod + mod) % mod;
}
signed main() {
n = read(), m = read();
int ans1 = solve(n) * solve(m) % mod, ans2 = 0;
for (int l = 1, r, now1, now2, now3, now4; l <= min(n, m); l = r + 1) {
r = min(n / (n / l), m / (m / l));
now1 = n * m % mod * (r - l + 1) % mod;
now2 = ((n / l) * (m / l) % mod * sum2(l, r) % mod + mod) % mod;
now3 = ((n / l) * m % mod + (m / l) * n % mod) * sum(l, r) % mod;
now4 = (now1 + now2 - now3 + mod) % mod;
ans2 = (ans2 + now4) % mod;
}
cout << ((ans1 - ans2) % mod + mod) % mod;
return 0;
}

本文详细解析了使用数论分块技巧求解特定数学问题的方法,包括求和公式和时间复杂度分析,提供了完整的代码实现。

144

被折叠的 条评论
为什么被折叠?



