【ACM数论】莫比乌斯反演

莫比乌斯反演

反演

​ 举个例子:
已知 g ( n ) 的前缀和 f ( n ) = ∑ i = 1 n g ( i ) ,则可以通过 f 反求 g = > g ( n ) = f ( n ) − f ( n − 1 ) 已知g(n)的前缀和f(n)=\sum_{i=1}^ng(i),则可以通过f反求g =>g(n)=f(n)-f(n-1) 已知g(n)的前缀和f(n)=i=1ng(i),则可以通过f反求g=>g(n)=f(n)f(n1)
​ 像这样的过程就是反演,换言之,就是一个函数 f f f g g g推导而来,已知 f f f,求 g g g

1、提出一个问题


已知 g ( n ) 的因数和 f ( n ) = ∑ d ∣ n g ( d ) , 如何通过 f 反求 g 已知g(n)的因数和f(n)=\sum_{d|n}g(d),如何通过f反求g 已知g(n)的因数和f(n)=dng(d),如何通过f反求g

1.1、先模拟出f

{ f ( 1 ) = g ( 1 ) f ( 2 ) = g ( 1 ) + g ( 2 ) f ( 3 ) = g ( 1 ) + g ( 3 ) f ( 4 ) = g ( 1 ) + g ( 2 ) + g ( 4 ) f ( 5 ) = g ( 1 ) + g ( 5 ) f ( 6 ) = g ( 1 ) + g ( 2 ) + g ( 3 ) + g ( 6 ) f ( 7 ) = g ( 1 ) + g ( 7 ) . . . . . \begin{cases} f(1)=g(1)\\ f(2)=g(1)+g(2)\\ f(3)=g(1)+g(3)\\ f(4)=g(1)+g(2)+g(4)\\ f(5)=g(1)+g(5)\\ f(6)=g(1)+g(2)+g(3)+g(6)\\ f(7)=g(1)+g(7)\\ ..... \end{cases} f(1)=g(1)f(2)=g(1)+g(2)f(3)=g(1)+g(3)f(4)=g(1)+g(2)+g(4)f(5)=g(1)+g(5)f(6)=g(1)+g(2)+g(3)+g(6)f(7)=g(1)+g(7).....

​ 通过以上的等式,可以将相应的g求出:
{ g ( 1 ) = f ( 1 ) g ( 2 ) = f ( 2 ) − f ( 1 ) g ( 3 ) = f ( 3 ) − f ( 1 ) g ( 4 ) = f ( 4 ) − f ( 2 ) g ( 5 ) = f ( 5 ) − f ( 1 ) g ( 6 ) = f ( 6 ) − f ( 3 ) − f ( 2 ) + f ( 1 ) g ( 7 ) = f ( 7 ) − f ( 1 ) . . . . . \begin{cases} g(1)=f(1)\\ g(2)=f(2)-f(1)\\ g(3)=f(3)-f(1)\\ g(4)=f(4)-f(2)\\ g(5)=f(5)-f(1)\\ g(6)=f(6)-f(3)-f(2)+f(1)\\ g(7)=f(7)-f(1)\\ ..... \end{cases} g(1)=f(1)g(2)=f(2)f(1)g(3)=f(3)f(1)g(4)=f(4)f(2)g(5)=f(5)f(1)g(6)=f(6)f(3)f(2)+f(1)g(7)=f(7)f(1).....
​ 通过这个模拟可以看出一丝小小的规律:

​ 将 n n n先改写成 p 1 α 1 p 2 α 2 p 3 α 3 . . . . p k α k p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k} p1α1p2α2p3α3....pkαk,然后代入 g ( n ) g(n) g(n),根据上面的模拟将 g ( n ) g(n) g(n)展开
g ( n ) = g ( p 1 α 1 p 2 α 2 p 3 α 3 . . . . p k α k ) = f ( p 1 α 1 p 2 α 2 p 3 α 3 . . . . p k α k ) − f ( p 1 α 1 − 1 p 2 α 2 p 3 α 3 . . . . p k α k ) − f ( p 1 α 1 p 2 α 2 − 1 p 3 α 3 . . . . p k α k ) − f ( p 1 α 1 p 2 α 2 p 3 α 3 − 1 . . . . p k α k ) − f ( p 1 α 1 p 2 α 2 p 3 α 3 . . . . p k α k − 1 ) + f ( p 1 α 1 − 1 p 2 α 2 − 1 p 3 α 3 . . . . p k α k ) + f ( p 1 α 1 p 2 α 2 p 3 α 3 − 1 . . . . p k α k ) + . . . . . + f ( . . . . . p i α i − 1 . . . . p j α j − 1 . . . . . ) g(n)=g(p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k})\\ =f(p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k})-f(p_1^{\alpha_1-1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k})-f(p_1^{\alpha_1}p_2^{\alpha_2-1}p_3^{\alpha_3}....p_k^{\alpha_k}) -f(p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3-1}....p_k^{\alpha_k}) \\-f(p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k-1}) \\+f(p_1^{\alpha_1-1}p_2^{\alpha_2-1}p_3^{\alpha_3}....p_k^{\alpha_k})+f(p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3-1}....p_k^{\alpha_k})+..... +f(.....p_{i}^{\alpha_i-1}....p_j^{\alpha_j-1}.....) g(n)=g(p1α1p2α2p3α3....pkαk)=f(p1α1p2α2p3α3....pkαk)f(p1α11p2α2p3α3....pkαk)f(p1α1p2α21p3α3....pkαk)f(p1α1p2α2p3α31....pkαk)f(p1α1p2α2p3α3....pkαk1)+f(p1α11p2α21p3α3....pkαk)+f(p1α1p2α2p3α31....pkαk)+.....+f(.....piαi1....pjαj1.....)

1.2、浓缩展开式

​ 我们通过上面的模拟可以确定最终反演的 g g g,一定是长成上面那个复杂的等式的样子,但是这样一个等式不怎么好记,因此我们将上述展开式进行抽象:
g ( p 1 α 1 p 2 α 2 p 3 α 3 . . . . p k α k ) = ∑ s ⊆ { 1 , 2 , 3 , . . k } ( − 1 ) ∣ k ∣ f ( p 1 α 1 − i 1 p 2 α 2 − i 2 p 3 α 3 − i 3 . . . . p k α k − i k ) 其中 { i j = 1 , j ∈ S i j = 0 , 其他 g(p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k})=\sum_{s\subseteq\{1,2,3,..k\}}(-1)^{|k|}f(p_1^{\alpha_1-i_1}p_2^{\alpha_2-i_2}p_3^{\alpha_3-i_3}....p_k^{\alpha_k-i_k}) \\ 其中 \begin{cases} i_j=1,j\in S \\ i_j=0,其他 \end{cases} g(p1α1p2α2p3α3....pkαk)=s{1,2,3,..k}(1)kf(p1α1i1p2α2i2p3α3i3....pkαkik)其中{ij=1,jSij=0,其他
碰巧!!!在数论有这样一个函数——莫比乌斯函数 μ \mu μ

1.3、莫比乌斯函数


μ ( n ) = { 1 , n = 1 ( − 1 ) k , n = p 1 α 1 p 2 α 2 p 3 α 3 . . . . p k α k 且 α i = 1 0 ,其他 \mu(n)= \begin{cases} 1,n=1\\ (-1)^k,n=p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k}且\alpha_i=1 \\ 0,其他 \end{cases} μ(n)= 1,n=1(1)k,n=p1α1p2α2p3α3....pkαkαi=10,其他
​ 这个时候我们便可以将 ( − 1 ) ∣ k ∣ (-1)^{|k|} (1)k μ ( n ) \mu(n) μn进行替换


g ( p 1 α 1 p 2 α 2 p 3 α 3 . . . . p k α k ) = ∑ s ⊆ { 1 , 2 , 3 , . . k } μ ( p 1 i 1 p 2 i 2 p 3 i 3 . . . . p k i k ) f ( p 1 α 1 − i 1 p 2 α 2 − i 2 p 3 α 3 − i 3 . . . . p k α k − i k ) 再化简: g ( n ) = ∑ d ∣ n μ ( n d ) f ( d ) g(p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}....p_k^{\alpha_k})=\sum_{s\subseteq\{1,2,3,..k\}}\mu(p_1^{i_1}p_2^{i_2}p_3^{i_3}....p_k^{i_k}) f(p_1^{\alpha_1-i_1}p_2^{\alpha_2-i_2}p_3^{\alpha_3-i_3}....p_k^{\alpha_k-i_k}) \\ 再化简:\\ g(n)=\sum_{d|n}\mu(\frac{n}{d})f(d) g(p1α1p2α2p3α3....pkαk)=s{1,2,3,..k}μ(p1i1p2i2p3i3....pkik)f(p1α1i1p2α2i2p3α3i3....pkαkik)再化简:g(n)=dnμ(dn)f(d)
​ 举个例子便可知道是否正确了:


例子: g ( 6 ) = μ ( 1 ) f ( 6 ) + μ ( 2 ) f ( 3 ) + μ ( 3 ) f ( 2 ) + μ ( 6 ) f ( 1 ) = f ( 6 ) − f ( 3 ) − f ( 2 ) + f ( 1 ) 例子:g(6)=\mu(1)f(6)+\mu(2)f(3)+\mu(3)f(2)+\mu(6)f(1)\\ =f(6)-f(3)-f(2)+f(1) 例子:g(6)=μ(1)f(6)+μ(2)f(3)+μ(3)f(2)+μ(6)f(1)=f(6)f(3)f(2)+f(1)

2、莫比乌斯反演

​ 通过上述过程我们便证明了定理1:

2.1、定理一:

已知 g ( n ) 的因数和 f ( n ) = ∑ d ∣ n g ( d ) , 则 g ( n ) = ∑ d ∣ n μ ( n d ) f ( d ) 已知g(n)的因数和f(n)=\sum_{d|n}g(d),则g(n)=\sum_{d|n}\mu(\frac{n}{d})f(d) 已知g(n)的因数和f(n)=dng(d),g(n)=dnμ(dn)f(d)

​ 除此之外,还有一个常见的

2.2、定理二:

有两个函数 f , g , 且存在正整数 N ,对于所有 n > N , f ( n ) = g ( n ) = 0 , 则 : f ( n ) = ∑ n ∣ m , m ≤ N g ( m )    ⟺    g ( n ) = ∑ n ∣ m , m ≤ N μ ( m n ) f ( m ) 有两个函数f,g,且存在正整数N,对于所有n>N,f(n)=g(n)=0,则: \\ f(n)=\sum_{n|m,m\leq N}g(m) \iff g(n)=\sum_{n|m,m\leq N}\mu(\frac{m}{n})f(m) 有两个函数f,g,且存在正整数N,对于所有n>N,f(n)=g(n)=0,:f(n)=nm,mNg(m)g(n)=nm,mNμ(nm)f(m)

​ 证明的方式和定理一异曲同工。

3、莫反好题:

3.1、牛客14648

题目连接:https://ac.nowcoder.com/acm/problem/14648


题目大意:有两个序列 a , b ,问:有多少个序列 < x , y > 满足 g c d ( x , y ) = 1 且 a b x = b a y 题目大意:有两个序列a,b,问:有多少个序列<x,y>满足gcd(x,y)=1 且 a_{b_x}=b_{a_y} 题目大意:有两个序列a,b,问:有多少个序列<x,y>满足gcd(x,y)=1abx=bay

这道题的意思等价于求 ∑ 1 ≤ x ≤ n , 1 ≤ y ≤ n [ a b x = b a y ] [ g c d ( x , y ) = 1 ] 那么设 f ( D ) = ∑ 1 ≤ x ≤ n , 1 ≤ y ≤ n [ a b x = b a y ] [ g c d ( x , y ) = D ] 那么根据莫比乌斯反演定理二有: g ( d ) = ∑ d ∣ D f ( D ) 由于 { D ∣ x D ∣ y 所以有 { d ∣ x d ∣ y 所以 g ( d ) = ∑ d ∣ x , d ∣ y [ a b x = b a y ] 这样一来 g 函数就很好算(时间复杂度 O ( n l o g n ) ),然后利用反演即可求出 f 函数 由定理二可得 f ( D ) = ∑ D ∣ d , d ≤ n μ ( d D ) g ( d ) 由于我们所求为 f ( 1 ) ,因此将 D = 1 代入即可 所以 f ( 1 ) = ∑ 1 ∣ d , d ≤ n μ ( d ) g ( d ) 然可以利用 μ 函数是积性函数的特性将莫比乌斯函数打表打出来 ( 时间复杂度 O ( n ) ) 所以最后的时间复杂度为 O ( n l o g n + n ) 这道题的意思等价于求\sum_{1\leq x\leq n,1\leq y\leq n}[a_{b_x}=b_{a_y}][gcd(x,y)=1] \\ 那么设f(D)=\sum_{1\leq x\leq n,1\leq y\leq n}[a_{b_x}=b_{a_y}][gcd(x,y)=D] \\ 那么根据莫比乌斯反演定理二有: g(d)=\sum_{d|D}f(D)\\ 由于 \begin{cases} D|x \\ D|y \end{cases} \\所以有 \begin{cases} d|x \\ d|y \end{cases} \\所以g(d)=\sum_{ d|x, d|y }[a_{b_x}=b_{a_y}] \\ 这样一来g函数就很好算(时间复杂度O(nlogn)),然后利用反演即可求出f函数 \\ 由定理二可得 f(D)=\sum_{D|d,d\leq n}\mu(\frac{d}{D})g(d) \\由于我们所求为f(1),因此将D=1代入即可 \\ 所以f(1)=\sum_{1|d,d\leq n}\mu(d)g(d) \\然可以利用\mu函数是积性函数的特性将莫比乌斯函数打表打出来(时间复杂度O(n)) \\所以最后的时间复杂度为O(nlogn+n) 这道题的意思等价于求1xn,1yn[abx=bay][gcd(x,y)=1]那么设f(D)=1xn,1yn[abx=bay][gcd(x,y)=D]那么根据莫比乌斯反演定理二有:g(d)=dDf(D)由于{DxDy所以有{dxdy所以g(d)=dx,dy[abx=bay]这样一来g函数就很好算(时间复杂度O(nlogn)),然后利用反演即可求出f函数由定理二可得f(D)=Dd,dnμ(Dd)g(d)由于我们所求为f(1),因此将D=1代入即可所以f(1)=1∣d,dnμ(d)g(d)然可以利用μ函数是积性函数的特性将莫比乌斯函数打表打出来(时间复杂度O(n))所以最后的时间复杂度为O(nlogn+n)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string.h>
using namespace std;
#define int long long
const int maxn = 1e5 + 10;
vector<int> primes;
bool isnp[maxn];
int mu[maxn];
int a[maxn];
int b[maxn];
void EularMu(int n)//求莫比乌斯函数
{
    mu[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        if (!isnp[i])
        {
            primes.push_back(i);
            mu[i] = -1;
        }
        for (auto p : primes)
        {
            if (i * p > n)
                break;
            isnp[p * i] = 1;
            if (i % p == 0)
            {
                mu[i*p]=0;
                break;
            }
            mu[i * p] = -mu[i] ;
        }
    }
}
int num[maxn];
int getg(int d, int n)//求g函数
{
    int ans = 0;
    for (int x = d; x <= n; x += d)
    {
        num[a[b[x]]]++;
    }
    for (int y = d; y <= n; y += d)
    {
        ans += num[b[a[y]]];
    }
    for (int x = d; x <= n; x += d)
    {
        num[a[b[x]]]--;
    }
    return ans;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    EularMu(maxn);
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i];
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        ans += mu[i] * getg(i, n);
    }
    cout << ans << endl;
    return 0;
}
3.2、AtCoder Grand Contest 038C

题目连接:https://atcoder.jp/contests/agc038/tasks/agc038_c
给一个长度为 n 的序列 a 0 , a 1 , a 2 , . . . , a n − 1 求 ∑ i = 0 n − 2 ∑ j = i + 1 n − 1 l c m ( a i , a j )   m o d   998244353 给一个长度为 n的序列 a_0,a_1,a_2,...,a_{n−1}\\ 求∑_{i=0}^{n−2}∑_{j=i+1}^{n−1}lcm(a_i,a_j)\ mod\ 998244353 给一个长度为n的序列a0,a1,a2,...,an1i=0n2j=i+1n1lcm(ai,aj) mod 998244353

解:首先利用和式的性质: ∑ i = 0 n − 1 ∑ j = 0 n − 1 a i j = 2 ∑ i = 0 n − 2 ∑ j = i + 1 n − 1 a i j + ∑ i = 0 n − 1 a i i 这个性质可以想象成一个大矩阵 a i j 求和,这个和式等价于 < 整个矩阵的和 = 右上角 + 左下角 + 对角线 > ∴ ∑ i = 0 n − 2 ∑ j = i + 1 n − 1 l c m ( a i , a j ) = ∑ i = 0 n − 1 ∑ j = 0 n − 1 l c m ( a i , a j ) − ∑ i = 0 n − 1 a i 2 由于 ∑ i = 0 n − 1 a i 很好算,所以这个问题等价于如何求 ∑ i = 0 n − 1 ∑ j = 0 n − 1 l c m ( a i , a j ) 又 ∵ l c m ( a i , a j ) = a i ∗ a j g c d ( a i , a j ) ∴ ∑ i = 0 n − 1 ∑ j = 0 n − 1 l c m ( a i , a j ) = ∑ i = 0 n − 1 ∑ j = 0 n − 1 a i ∗ a j g c d ( a i , a j ) ∴ ∑ i = 0 n − 1 ∑ j = 0 n − 1 l c m ( a i , a j ) = ∑ d = 1 m a x ( a 0 , a 2 . . a n − 1 ) 1 d ∑ i = 0 n − 1 ∑ j = 0 n − 1 a i ∗ a j [ g c d ( a i , a j ) = d ] 这样一来,这个问题感觉就变得套路化了! 上套路: 设 f ( d ) = ∑ i = 0 n − 1 ∑ j = 0 n − 1 a i ∗ a j [ g c d ( a i , a j ) = d ] 做一个倍数和函数 g 则 g ( d ) = ∑ d ∣ D f ( D ) = ∑ d ∣ D ∑ i = 0 n − 1 ∑ j = 0 n − 1 a i ∗ a j [ g c d ( a i , a j ) = D ] ∵ D ∣ a i , D ∣ a j ∴ d ∣ a i , d ∣ a j ∴ g ( d ) = ∑ d ∣ D ∑ i = 0 n − 1 a i [ d ∣ a i ] ∑ j = 0 n − 1 a j [ d ∣ a j ] ∴ g ( d ) = ∑ d ∣ D ( ∑ i = 0 n − 1 a i [ d ∣ a i ] ) 2 这样一来通过枚举 d 就可以在 O ( ( m a x ( a i ) ) l o g ( m a x ( a i ) ) ) 的时间复杂度下通过打表打出 g 函数 利用莫比乌斯反演定理二可得: f ( d ) = ∑ d ∣ D μ ( D d ) g ( D ) ∴ ∑ i = 0 n − 1 ∑ j = 0 n − 1 l c m ( a i , a j ) = ∑ d = 1 m a x ( a 0 , a 2 . . a n − 1 ) 1 d ∑ d ∣ D μ ( D d ) g ( D ) ∴ ∑ i = 0 n − 2 ∑ j = i + 1 n − 1 l c m ( a i , a j ) = ∑ d = 1 m a x ( a 0 , a 2 . . a n − 1 ) 1 d ∑ d ∣ D μ ( D d ) g ( D ) − ∑ i = 0 n − 1 a i 2 积性函数 μ 可以用欧拉筛在线性的时间 o ( n ) 内打表打出来, g 函数也是在 O ( n l o g n ) 的时间复杂度打表预处理 同理最后这个 ∑ d = 1 m a x ( a 0 , a 2 . . a n − 1 ) 1 d ∑ d ∣ D μ ( D d ) g ( D ) 也可以在 o ( n l o g n ) 的时间复杂度求出来 因此这个复杂的玩意儿可以在 O ( n l o g n ) 的时间复杂度下解决!!! 最后还需要注意一下,此题还有有一个取模的操作 对于此题分数取模,最好预先打表处理逆元,用一个 i n v 数组保存,不然会超时 解:首先利用和式的性质:\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}a_{ij}=2\sum_{i=0}^{n-2}\sum_{j=i+1}^{n-1}a_{ij}+\sum_{i=0}^{n-1}a_{ii} \\这个性质可以想象成一个大矩阵a_{ij}求和,这个和式等价于<整个矩阵的和= 右上角+左下角+对角线> \\ ∴∑_{i=0}^{n−2}∑_{j=i+1}^{n−1}lcm(a_i,a_j)=\frac{∑_{i=0}^{n−1}∑_{j=0}^{n−1}lcm(a_i,a_j)-\sum_{i=0}^{n-1}a_i}{2} \\ 由于\sum_{i=0}^{n-1}a_i很好算,所以这个问题等价于如何求∑_{i=0}^{n−1}∑_{j=0}^{n−1}lcm(a_i,a_j) \\又∵lcm(a_i,a_j)=\frac{a_i*a_j}{gcd(a_i,a_j)} \\∴∑_{i=0}^{n−1}∑_{j=0}^{n−1}lcm(a_i,a_j)=∑_{i=0}^{n−1}∑_{j=0}^{n−1}\frac{a_i*a_j}{gcd(a_i,a_j)} \\∴∑_{i=0}^{n−1}∑_{j=0}^{n−1}lcm(a_i,a_j)=\sum_{d=1}^{max(a_0,a_2..a_{n-1})}\frac{1}{d}∑_{i=0}^{n−1}∑_{j=0}^{n−1}a_i*a_j[gcd(a_i,a_j)=d] \\这样一来,这个问题感觉就变得套路化了! \\上套路: \\设f(d)=∑_{i=0}^{n−1}∑_{j=0}^{n−1}a_i*a_j[gcd(a_i,a_j)=d] \\做一个倍数和函数g\\ 则g(d)=\sum_{d|D}f(D)=\sum_{d|D}∑_{i=0}^{n−1}∑_{j=0}^{n−1}a_i*a_j[gcd(a_i,a_j)=D] \\ ∵D|a_i,D|a_j \\ ∴d|a_i,d|a_j \\ ∴g(d)=\sum_{d|D}∑_{i=0}^{n−1}a_i[d|a_i]∑_{j=0}^{n−1}a_j[d|a_j] \\ ∴g(d)=\sum_{d|D}(∑_{i=0}^{n−1}a_i[d|a_i])^2 \\这样一来通过枚举d就可以在O((max(a_i))log(max(a_i)))的时间复杂度下通过打表打出g函数 \\利用莫比乌斯反演定理二可得: \\f(d)=\sum_{d|D}\mu(\frac{D}{d})g(D) \\∴∑_{i=0}^{n−1}∑_{j=0}^{n−1}lcm(a_i,a_j)=\sum_{d=1}^{max(a_0,a_2..a_{n-1})}\frac{1}{d}\sum_{d|D}\mu(\frac{D}{d})g(D) \\ ∴∑_{i=0}^{n−2}∑_{j=i+1}^{n−1}lcm(a_i,a_j)=\frac{\sum_{d=1}^{max(a_0,a_2..a_{n-1})}\frac{1}{d}\sum_{d|D}\mu(\frac{D}{d})g(D)-\sum_{i=0}^{n-1}a_i}{2} \\ 积性函数\mu可以用欧拉筛在线性的时间o(n)内打表打出来,g函数也是在O(nlogn)的时间复杂度打表预处理 \\同理最后这个\sum_{d=1}^{max(a_0,a_2..a_{n-1})}\frac{1}{d}\sum_{d|D}\mu(\frac{D}{d})g(D)也可以在o(nlogn)的时间复杂度求出来 \\因此这个复杂的玩意儿可以在O(nlogn)的时间复杂度下解决!!! \\最后还需要注意一下,此题还有有一个取模的操作 \\对于此题分数取模,最好预先打表处理逆元,用一个inv数组保存,不然会超时 解:首先利用和式的性质:i=0n1j=0n1aij=2i=0n2j=i+1n1aij+i=0n1aii这个性质可以想象成一个大矩阵aij求和,这个和式等价于<整个矩阵的和=右上角+左下角+对角线>i=0n2j=i+1n1lcm(ai,aj)=2i=0n1j=0n1lcm(ai,aj)i=0n1ai由于i=0n1ai很好算,所以这个问题等价于如何求i=0n1j=0n1lcm(ai,aj)lcm(ai,aj)=gcd(ai,aj)aiaji=0n1j=0n1lcm(ai,aj)=i=0n1j=0n1gcd(ai,aj)aiaji=0n1j=0n1lcm(ai,aj)=d=1max(a0,a2..an1)d1i=0n1j=0n1aiaj[gcd(ai,aj)=d]这样一来,这个问题感觉就变得套路化了!上套路:f(d)=i=0n1j=0n1aiaj[gcd(ai,aj)=d]做一个倍数和函数gg(d)=dDf(D)=dDi=0n1j=0n1aiaj[gcd(ai,aj)=D]Dai,Dajdai,dajg(d)=dDi=0n1ai[dai]j=0n1aj[daj]g(d)=dD(i=0n1ai[dai])2这样一来通过枚举d就可以在O((max(ai))log(max(ai)))的时间复杂度下通过打表打出g函数利用莫比乌斯反演定理二可得:f(d)=dDμ(dD)g(D)i=0n1j=0n1lcm(ai,aj)=d=1max(a0,a2..an1)d1dDμ(dD)g(D)i=0n2j=i+1n1lcm(ai,aj)=2d=1max(a0,a2..an1)d1dDμ(dD)g(D)i=0n1ai积性函数μ可以用欧拉筛在线性的时间o(n)内打表打出来,g函数也是在O(nlogn)的时间复杂度打表预处理同理最后这个d=1max(a0,a2..an1)d1dDμ(dD)g(D)也可以在o(nlogn)的时间复杂度求出来因此这个复杂的玩意儿可以在O(nlogn)的时间复杂度下解决!!!最后还需要注意一下,此题还有有一个取模的操作对于此题分数取模,最好预先打表处理逆元,用一个inv数组保存,不然会超时

下面贴上代码(加了注释):

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
#define int long long
const int maxn = 1e6 + 10;
const int mod = 998244353;
vector<int> primes;
bool isnp[maxn];
int mu[maxn];
int a[maxn];
int gf[maxn];
int cnt[maxn];
int inv[maxn];
void Eular_mu(int n)//欧拉筛求莫比乌斯函数
{
    mu[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        if (!isnp[i])
        {
            primes.push_back(i);
            mu[i] = -1;
        }
        for (auto p : primes)
        {
            if (i * p > n)
                break;
            isnp[i * p] = 1;
            if (i % p == 0)
            {
                mu[i * p] = 0;
                break;
            }
            mu[i * p] = -mu[i];
        }
    }
}
int qp(int a, int x)//用快速幂
{
    int ans = 1;
    while (x)
    {
        if (x & 1)
        {
            ans = ans * a % mod;
        }
        a = a * a % mod;
        x >>= 1;
    }
    return ans;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin >> n;
    int maxx = 0;
    int sum = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        maxx = max(a[i], maxx);
        sum += a[i];
        cnt[a[i]]++;//记录a[i]的数量
    }
    Eular_mu(maxn);
    for(int i=1;i<=maxn;i++){//快速幂套费马小定理初始化逆元
        inv[i]=qp(i,mod-2);
    }
    for (int d = 1; d <= maxx; d++)//求g函数
    {
        for (int i = d; i <= maxx; i += d)
        {
            gf[d] = (gf[d] + i * cnt[i] % mod) % mod;
//由于是枚举d的倍数,如果符合条件一定存在a[i]和此时d的倍数相等,这个时候cnt的作用体现出来
//利用cnt便可以直接求和
        }
        gf[d] = gf[d] * gf[d] % mod;
    }
    int ans = 0;
    for (int d = 1; d <= maxx; d++)
    {
        for (int i = d; i <= maxx; i += d)
        {
            ans = (ans + mu[i / d] * gf[i] %mod* inv[d] % mod) % mod;
//同理枚举d的倍数,原理和g函数相似,最后直接套推出来的公式
        }
    }
    cout << (ans - sum%mod+mod ) % mod * inv[2] % mod << endl;
//sum容易吧mod爆了,一定要取模
    return 0;
}
  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值