【BZOJ2154】Crash的数字表格

【BZOJ2154】Crash的数字表格

题面

bzoj

洛谷

题解

不妨设(nleq m)

题目是求:

[sum_{i=1}^nsum_{j=1}^mlcm(i,j) ]

还是照常推式子qaq

[sum_{i=1}^nsum_{j=1}^mfrac{ij}{gcd(i,j)}\ sum_{d=1}^nsum_{i=1}^nsum_{j=1}^m[gcd(i,j)==d]frac{ij}{d}\ sum_{d=1}^nsum_{i=1}^{n/d}sum_{j=1}^{m/d}[gcd(i,j)==1]ijd\ sum_{d=1}^ndsum_{i=1}^{n/d}sum_{j=1}^{m/d}[gcd(i,j)==1]ij ]

暂时不管前面的,先搞后面的一坨

(x=n/d,y=m/d)

并且设

[f(k)=sum_{i=1}^xsum_{j=1}^y[gcd(i,j)==k]ij\ g(k)=sum_{k|d}f(d) ]

常见套路

[g(k)=sum_{i=1}^xsum_{j=1}^y[k|gcd(i,j)]ij ]

提出(k)

[g(k)=k^2sum_{i=1}^{x/k}sum_{j=1}^{y/k}[1|gcd(i,j)]ij\ g(k)=k^2sum_{i=1}^{x/k}sum_{j=1}^{y/k}ij ]

这个就是两个等差数列相乘。

要求的东西变为

[f(1)=sum_{i=1}^xmu(i)g(i) ]

问题解决很多了,但是还必须要往下

[ans=sum_{d=1}^ndsum_{i=1}^{n/d}sum_{j=1}^{m/d}[gcd(i,j)==1]ij ]

看看(f(1))是什么

[f(1)=sum_{i=1}^xmu(i)i^2sum_{i=1}^{x/d}sum_{j=1}^{y/d}ij ]

里外都可以数论分块,总复杂度(O(n))

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm> 
using namespace std;
const int Mod = 20101009;
const int MAX_N = 1e7 + 5; 
int N = 1e7, M, mu[MAX_N], prime[MAX_N], num; 
bool is_prime[MAX_N];
int s[MAX_N]; 
void sieve() {
    for (int i = 1; i <= N; i++) is_prime[i] = 1; 
    is_prime[1] = 0, mu[1] = 1; 
    for (int i = 2; i <= N; i++) {
        if (is_prime[i]) { prime[++num] = i, mu[i] = -1; }
        for (int j = 1; j <= num && i * prime[j] <= N; j++) { 
            is_prime[i * prime[j]] = 0; 
            if (i % prime[j]) mu[i * prime[j]] = -mu[i]; 
            else { mu[i * prime[j]] = 0; break; } 
        } 
    } 
}
int solve(int x, int y) { 
    int ans = 0;
    for (int l = 1, r; l <= x; l = r + 1) { 
        r = min(x / (x / l), y / (y / l)); 
        int res = 1ll * (1ll * (1 + x / l) * (x / l) / 2 % Mod) * (1ll * (1 + y / l) * (y / l) / 2 % Mod) % Mod;
        ans = (1ll * (s[r] - s[l - 1]) % Mod * res % Mod + ans) % Mod; 
    }
    return (ans + Mod) % Mod; 
} 
int main () {
    sieve(); 
    cin >> N >> M;
    if (N > M) swap(N, M); 
    for (int i = 1; i <= N; i++) s[i] = (s[i - 1] + 1ll * i * i % Mod * mu[i] % Mod + Mod) % Mod;
    int ans = 0; 
    for (int l = 1, r; l <= N; l = r + 1) { 
        r = min(N / (N / l), M / (M / l)); 
        int res = 1ll * (l + r) * (r - l + 1) / 2 % Mod; 
        ans = (ans + 1ll * solve(N / l, M / l) * res % Mod) % Mod; 
    }
    printf("%d
", ans); 
    return 0; 
} 
原文地址:https://www.cnblogs.com/heyujun/p/10189750.html