题解 P2260 【[清华集训2012]模积和】

GKxx

2019-04-14 12:11:49

Solution

可以说是最近做的几道数学题里比较弱智的了 基本上就是[余数求和](https://www.luogu.org/problemnew/show/P2261)的加强版,没有设置什么障碍 $ans=\sum\limits_{i=1}^n\sum\limits_{j=1}^m(n\bmod i)(m\bmod j)-\sum\limits_{i=1}^{\min(n,m)}(n\bmod i)(m\bmod i)$ 不妨记为$ans=a-b$,分别计算 $a=\sum\limits_{i=1}^n(n\bmod i)\sum\limits_{j=1}^m(m\bmod j)$ $=\sum\limits_{i=1}^n(n-i\lfloor\frac{n}{i}\rfloor)\sum\limits_{j=1}^m(m-j\lfloor\frac{m}{j}\rfloor)$ 整除分块即可解决,就相当于把余数求和跑两遍 不妨设$k=\min(n,m)$那么 $b=\sum\limits_{i=1}^k(n-i\lfloor\frac{n}{i}\rfloor)(m-i\lfloor\frac{m}{i}\rfloor)$ $=\sum\limits_{i=1}^k(mn-mi\lfloor\frac{n}{i}\rfloor-ni\lfloor\frac{m}{i}\rfloor+i^2\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor)$ $=kmn-\sum\limits_{i=1}^k(mi\lfloor\frac{n}{i}\rfloor+ni\lfloor\frac{m}{i}\rfloor-i^2\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor)$ 整除分块即可解决。 另外两个需要知道的公式: $\sum\limits_{i=1}^ni=\frac{n(n+1)}{2}$ $\sum\limits_{i=1}^ni^2=\frac{n(n+1)(2n+1)}{6}$ 前者使用的时候直接用$\text{long long}$就行了,但是后者需要求$6$的逆元,因为三个数相乘会爆$\text{long long}$。 ```cpp #include <cctype> #include <cstdio> #include <climits> #include <algorithm> template <typename T> inline void read(T& x) { int f = 0, c = getchar(); x = 0; while (!isdigit(c)) f |= c == '-', c = getchar(); while (isdigit(c)) x = x * 10 + c - 48, c = getchar(); if (f) x = -x; } template <typename T, typename... Args> inline void read(T& x, Args&... args) { read(x); read(args...); } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + 48); } template <typename T> inline void writeln(T x) { write(x); puts(""); } template <typename T> inline bool chkmin(T& x, const T& y) { return y < x ? (x = y, true) : false; } template <typename T> inline bool chkmax(T& x, const T& y) { return x < y ? (x = y, true) : false; } typedef long long LL; const LL mod = 19940417; int n, m; int inv6 = 3323403; inline int s1(int l, int r) { return 1ll * (l + r) * (r - l + 1) / 2 % mod; } inline int s2(int l, int r) { auto f = [](int x) -> int { return 1ll * x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod; }; return ((f(r) - f(l - 1)) % mod + mod) % mod; } inline int calc(int n) { int ans = 1ll * n * n % mod; for (int l = 1, r; l <= n; l = r + 1) { r = n / (n / l); ans = (ans - 1ll * s1(l, r) * (n / l) % mod + mod) % mod; } return ans; } int main() { read(n, m); int ans = 1ll * calc(n) * calc(m) % mod; int mn = std::min(n, m); ans = (ans - 1ll * mn * n % mod * m % mod + mod) % mod; for (int l = 1, r; l <= mn; l = r + 1) { r = std::min(n / (n / l), m / (m / l)); ans = (ans + 1ll * s1(l, r) * (1ll * n * (m / l) % mod + 1ll * m * (n / l) % mod) % mod) % mod; ans = (ans - 1ll * s2(l, r) * (n / l) % mod * (m / l) % mod + mod) % mod; } writeln((ans % mod + mod) % mod); return 0; } ```