[BZOJ2154]Crash的数字表格(莫比乌斯反演)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=2154

Solution

显然是莫比乌斯反演

i = 1 N j = 1 M lcm ( i , j )

= i = 1 N j = 1 M i j gcd ( i , j )

d i = 1 N j = 1 M i j d [ gcd ( i , j ) = d ]

= d i = 1 N d j = 1 M d d i j [ gcd ( i , j ) = 1 ]

= d d i = 1 N d j = 1 M d i j k | gcd ( i , j ) μ ( k )

= d d k i = 1 , k | i N d j = 1 , k | j M d i j μ ( k )

= d d k k 2 S ( N d k ) S ( M d k ) μ ( k )

其中 S ( x ) = x ( x + 1 ) 2
发现下取整内的分母是乘积的形式,还是不好做。
所以设 T = d k
T k | T T k k 2 S ( N T ) S ( M T ) μ ( k )

= T T S ( N T ) S ( M T ) k | T k μ ( k )

再考虑求 f ( T ) = k | T k μ ( k )
对于任意的 gcd ( S , T ) = 1 ,都有:
f ( S T ) = k | S T k μ ( k )

d | S k | T d k μ ( d k )

= ( d | S μ ( d ) ) ( k | T μ ( k ) )

= f ( S ) f ( T )

我们得到: f 是积性函数。可以线性筛求。
f ( 1 ) = 1

n k 1 , f ( n k ) = 1 n

m m | n , f ( n m ) = f ( n )

gcd ( n , m ) = 1 , f ( n m ) = f ( n ) f ( m )

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
using namespace std;
const int MaxN = 1e7, N = 1e7 + 5, ZZQ = 20101009;
int n, m, tot, pri[N], zzq[N], ans;
bool mark[N];
void sieve() {
    int i, j;
    mark[0] = mark[zzq[1] = 1] = 1;
    For (i, 2, MaxN) {
        if (!mark[i]) zzq[pri[++tot] = i] = 1 - i + ZZQ;
        For (j, 1, tot) {
            if (1ll * i * pri[j] > MaxN) break;
            mark[i * pri[j]] = 1;
            if (i % pri[j] == 0) {
                zzq[i * pri[j]] = zzq[i];
                break;
            }
            else zzq[i * pri[j]] = 1ll * zzq[i] * zzq[pri[j]] % ZZQ;
        }
    }
}
int S(int n) {
    return (1ll * n * (n + 1) >> 1) % ZZQ;
}
int main() {
    int i;
    cin >> n >> m;
    sieve();
    For (i, 1, min(n, m))
        ans = (ans + 1ll * i * S(n / i) % ZZQ * S(m / i)
        % ZZQ * zzq[i] % ZZQ) % ZZQ;
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81358525
今日推荐