【数论+莫比乌斯反演】Exclusive Multiplication | gym103688E

【数论+莫比乌斯反演】Exclusive Multiplication | gym103688

前言

  • [ f ( x ) ] [f(x)] [f(x)] 表示艾弗森括号,若 f ( x ) f(x) f(x) 表达式为真,值为1,否则为0
    μ ( x ) \mu(x) μ(x) 表示莫比乌斯函数
    a ∣ b a|b ab 表示a整除b,即a是b的因子,b是a的倍数

题意

  • CF链接
    给定函数 f ( n ) f(n) f(n),即质因子分解后,指数取模 2 2 2后的乘积
    f ( n ) = ∏ i p i s i % 2 f(n)=\prod_{i}p_i^{s_i\%2} f(n)=ipisi%2
    给定长度为 n n n 的序列 b [ n ] b[n] b[n],求
    ∑ 1 ≤ i < j ≤ n f ( b i × b j ) ( m o d 1 e 9 + 7 ) \sum_{1\le i<j\le n}f(b_i \times b_j) \pmod{1e9+7} 1i<jnf(bi×bj)(mod1e9+7)
  • 1 ≤ n ≤ 2 ⋅ 1 0 5 1\le n\le 2\cdot 10^5 1n2105
    1 ≤ b i ≤ 2 ⋅ 1 0 5 1\le b_i\le 2\cdot 10^5 1bi2105

思路

  • 首先需要推一下 f ( a × b ) f(a\times b) f(a×b) 函数的性质
    f ( a × b ) = f ( ∏ i p i s i × ∏ j p j s j ) = f ( ∏ k p k s k i + s k j ) = ∏ k p k ( s k i + s k j ) % 2 = ∏ k l c m ( p k s k i % 2 , p k s k j % 2 ) g c d ( p k s k i % 2 , p k s k j % 2 ) = ∏ k l c m ( f ( p k s k i ) , f ( p k s k j ) ) g c d ( f ( p k s k i ) , f ( p k s k j ) ) = l c m ( f ( a ) , f ( b ) ) g c d ( f ( a ) , f ( b ) ) = f ( a ) × f ( b ) ( g c d ( f ( a ) , f ( b ) ) ) 2 \begin{aligned} f(a\times b)&=f(\prod_i p_i^{s_i} \times \prod_j p_j^{s_j})\\ &=f(\prod_k p_k^{s_{k_i}+s_{k_j}})\\ &=\prod_k p_k^{(s_{k_i}+s_{k_j})\%2}\\ &=\prod_k\frac{lcm(p_k^{s_{k_i}\%2},p_k^{s_{k_j}\%2})}{gcd(p_k^{s_{k_i}\%2},p_k^{s_{k_j}\%2})}\\ &=\prod_k \frac{lcm(f(p_k^{s_{k_i}}),f(p_k^{s_{k_j}}))}{gcd(f(p_k^{s_{k_i}}),f(p_k^{s_{k_j}}))}\\ &=\frac{lcm(f(a),f(b))}{gcd(f(a),f(b))}\\ &=\frac{f(a)\times f(b)}{\Big(gcd(f(a),f(b))\Big)^2} \end{aligned} f(a×b)=f(ipisi×jpjsj)=f(kpkski+skj)=kpk(ski+skj)%2=kgcd(pkski%2,pkskj%2)lcm(pkski%2,pkskj%2)=kgcd(f(pkski),f(pkskj))lcm(f(pkski),f(pkskj))=gcd(f(a),f(b))lcm(f(a),f(b))=(gcd(f(a),f(b)))2f(a)×f(b)
  • 主要考虑到单独考虑每个质因子,然后考虑指数取模2后运算有点类似于异或运算,所以可以改成 lcm 除以 gcd,然后再用 f f f 函数反替换。
  • 那么答案需要求的就是(以下表述省略取模运算):
    I = ∑ 1 ≤ i < j ≤ n f ( b i × b j ) = ∑ 1 ≤ i < j ≤ n f ( b i ) × f ( b j ) g c d ( f ( b i ) , f ( b j ) ) 2 = ∑ d = 1 ∑ 1 ≤ i < j ≤ n [ g c d ( f ( b i ) , f ( b j ) ) = d ] f ( b i ) × f ( b j ) d 2 = ∑ d = 1 1 2 ( ∑ i = 1 ∑ j = 1 [ g c d ( f ( b i ) , f ( b j ) ) = d ] f ( b i ) × f ( b j ) d 2 − ∑ p [ g c d ( f ( b p ) , f ( b p ) ) = d ] f ( b p ) 2 d 2 ) = 1 2 ∑ d = 1 ( ∑ i = 1 ∑ j = 1 [ g c d ( f ( b i ) , f ( b j ) ) = d ] f ( b i ) × f ( b j ) d 2 ) − 1 2 ∑ p ∑ d = 1 [ f ( b p ) = d ] f ( b p ) 2 d 2 = 1 2 ∑ d = 1 g ( d ) d 2 − n 2 \begin{aligned} I&=\sum_{1\le i<j\le n}f(b_i \times b_j)\\ &=\sum_{1\le i<j\le n} \frac{f(b_i)\times f(b_j)}{gcd(f(b_i),f(b_j))^2}\\ &=\sum_{d=1}\sum_{1\le i<j\le n} \Big[gcd(f(b_i),f(b_j))=d\Big]\frac{f(b_i)\times f(b_j)}{d^2}\\ &=\sum_{d=1}\frac{1}{2}\Big(\sum_{i=1}\sum_{j=1}\Big[gcd(f(b_i),f(b_j))=d\Big]\frac{f(b_i)\times f(b_j)}{d^2} - \sum_p[gcd(f(b_p),f(b_p))=d]\frac{f(b_p)^2}{d^2}\Big)\\ &=\frac{1}{2}\sum_{d=1}(\sum_{i=1}\sum_{j=1}\Big[gcd(f(b_i),f(b_j))=d\Big]\frac{f(b_i)\times f(b_j)}{d^2}) - \frac{1}{2}\sum_p\sum_{d=1}[f(b_p)=d]\frac{f(b_p)^2}{d^2}\\ &=\frac{1}{2}\sum_{d=1}\frac{g(d)}{d^2} -\frac{n}{2} \end{aligned} I=1i<jnf(bi×bj)=1i<jngcd(f(bi),f(bj))2f(bi)×f(bj)=d=11i<jn[gcd(f(bi),f(bj))=d]d2f(bi)×f(bj)=d=121(i=1j=1[gcd(f(bi),f(bj))=d]d2f(bi)×f(bj)p[gcd(f(bp),f(bp))=d]d2f(bp)2)=21d=1(i=1j=1[gcd(f(bi),f(bj))=d]d2f(bi)×f(bj))21pd=1[f(bp)=d]d2f(bp)2=21d=1d2g(d)2n
  • 注意到,首先是式子替换,然后套路枚举 g c d = d gcd=d gcd=d,然后把 1 ≤ i < j ≤ n 1\le i<j\le n 1i<jn 拆成了 1 ≤ i , j ≤ n 1\le i,j\le n 1i,jn 的部分,为了方便后续的计算。
    然后本质就是求上述的 g ( d ) g(d) g(d) 函数。
    g ( d ) = ∑ i = 1 ∑ j = 1 [ g c d ( f ( b i ) , f ( b j ) ) = d ] f ( b i ) × f ( b j ) g(d)=\sum_{i=1}\sum_{j=1}\Big[gcd(f(b_i),f(b_j))=d\Big]f(b_i)\times f(b_j) g(d)=i=1j=1[gcd(f(bi),f(bj))=d]f(bi)×f(bj)
  • 它不好算,我们看看它的和函数好不好算。
    G ( n ) = ∑ n ∣ d g ( d ) G(n)=\sum_{n|d}g(d) G(n)=ndg(d)
  • 继续计算
    G ( n ) = ∑ n ∣ d ∑ i = 1 ∑ j = 1 [ g c d ( f ( b i ) , f ( b j ) ) = d ] f ( b i ) × f ( b j ) = ∑ i = 1 ∑ j = 1 ∑ n ∣ d [ g c d ( f ( b i ) , f ( b j ) ) = d ] f ( b i ) × f ( b j ) = ∑ i = 1 ∑ j = 1 ∑ n ∣ g c d ( f ( b i ) , f ( b j ) ) f ( b i ) × f ( b j ) = ∑ i = 1 ∑ j = 1 ∑ n ∣ f ( b i ) 且 n ∣ f ( b j ) f ( b i ) × f ( b j ) = ( ∑ i = 1 [ n ∣ b i ] f ( b i ) ) 2 \begin{aligned} G(n)&=\sum_{n|d}\sum_{i=1}\sum_{j=1}\Big[gcd(f(b_i),f(b_j))=d\Big]f(b_i)\times f(b_j)\\ &=\sum_{i=1}\sum_{j=1}\sum_{n|d}\Big[gcd(f(b_i),f(b_j))=d\Big]f(b_i)\times f(b_j)\\ &=\sum_{i=1}\sum_{j=1}\sum_{n|gcd(f(b_i),f(b_j))}f(b_i)\times f(b_j)\\ &=\sum_{i=1}\sum_{j=1}\sum_{n|f(b_i)且n|f(b_j)}f(b_i)\times f(b_j)\\ &=(\sum_{i=1}\Big[n|b_i\Big]f(b_i))^2 \end{aligned} G(n)=ndi=1j=1[gcd(f(bi),f(bj))=d]f(bi)×f(bj)=i=1j=1nd[gcd(f(bi),f(bj))=d]f(bi)×f(bj)=i=1j=1ngcd(f(bi),f(bj))f(bi)×f(bj)=i=1j=1nf(bi)nf(bj)f(bi)×f(bj)=(i=1[nbi]f(bi))2
  • 最后一行有些巧妙。对于都是 n n n 的倍数的所有数字 f ( b i ) f(b_i) f(bi) 都放到一个集合中,然后取每对两两乘积的和,相当于求他们的和的平方,即:
    ( ∑ i x i ) 2 = ∑ i ∑ j x i x j = ∑ i x i 2 + 2 ∑ i < j x i x j (\sum_i x_i)^2=\sum_i \sum_j x_ix_j=\sum_i x_i^2+2\sum_{i<j}x_ix_j (ixi)2=ijxixj=ixi2+2i<jxixj
  • 而最后一行十分好计算,我们只需把 f ( x ) f(x) f(x) 存入桶中,可快速。
  • 最后,直接反演即可
    g ( n ) = ∑ n ∣ d μ ( d n ) G ( d ) g(n)=\sum_{n|d}\mu(\frac{d}{n})G(d) g(n)=ndμ(nd)G(d)

代码

  • 求所有的 f ( n ) f(n) f(n) 复杂度为 2 e 5 × n \sqrt{2e5} \times n 2e5 ×n (可缩小,但没必要)
    求所有的 G ( n ) G(n) G(n) 复杂度为 n log ⁡ n n\log n nlogn
    求所有的 g ( n ) g(n) g(n) 复杂度为 n log ⁡ n n\log n nlogn
    求所有的 μ ( n ) \mu(n) μ(n) 复杂度为 n n n,用欧拉筛
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){
    
    std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){
    
    std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 2e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-7;
const double PI = acos(-1);

ll qpow(ll a,ll n){
    
    /* */ll res = 1LL;while(n){
    
    if(n&1)res=res*a%MOD;a=a*a%MOD;n>>=1;}return res;}
ll qpow(ll a,ll n,ll p){
    
    a%=p;ll res = 1LL;while(n){
    
    if(n&1)res=res*a%p;a=a*a%p;n>>=1;}return res;}
ll npow(ll a,ll n){
    
    /* */ll res = 1LL;while(n){
    
    if(n&1)res=res*a;a=a*a;n>>=1;if(res<0||a<0)return 0;}return res;}
ll inv(ll a){
    
    /* */return qpow(a,MOD-2);}
ll inv(ll a,ll p){
    
    return qpow(a,p-2,p);}

bool vis[MAX];
int prime[MAX];
int mu[MAX];
int cnt;
void shai(int n){
    
    
    mu[1] = 1;
    for(int i = 2;i <= n;++i){
    
    
        if(!vis[i]){
    
    
            prime[++cnt] = i;
            mu[i] = -1;
        }
        for(int j = 1;j <= cnt && i * prime[j] <= n;++j){
    
    
            vis[i*prime[j]] = 1;
            if(i % prime[j])mu[i*prime[j]] = -mu[i];
            else {
    
    
            	mu[i*prime[j]] = 0;
                break;
            }
        }
    }
}

int bar[MAX];

int f(int x){
    
    
    int ans = 1;
    for(int i = 2;i * i <= x;++i){
    
    
        if(x % i == 0){
    
    
            int cnt = 0;
            while(x % i == 0){
    
    
                cnt++;
                x /= i;
            }
            if(cnt&1)ans *= i;
        }
    }
    if(x > 1)ans *= x;
    return ans;
}

ll G[MAX],g[MAX];
ll iv2[MAX];

void init(int n){
    
    
    for(int i = 1;i <= n;++i){
    
    
        iv2[i] = inv(i);
        iv2[i] = (iv2[i] * iv2[i]) % MOD;
    }
}

void cal_G(){
    
    
    for(int n = 1;n <= 200000;++n){
    
    
        for(int k = 1;n * k <= 200000;++k){
    
    
            G[n] = (G[n] + bar[n*k] * n % MOD * k % MOD) % MOD;
        }
        G[n] = G[n] * G[n] % MOD;
    }
}

void cal_g(){
    
    
    for(int n = 1;n <= 200000;++n){
    
    
        for(int k = 1;n * k <= 200000;++k){
    
    
            int d = n * k;
            g[n] = (g[n] + mu[k] * G[d] % MOD + MOD) % MOD;
        }
    }
}

int  main()
{
    
    
    IOS;
    shai(200000);
    init(200000);

    int n;cin >> n;
    for(int i = 1;i <= n;++i){
    
    
        int x;cin >> x;
        bar[f(x)]++;
    }

    cal_G();
    cal_g();

    ll ans = 0;

    for(int d = 1;d <= 200000;++d){
    
    
        ans = (ans + g[d] * iv2[d] % MOD);
    }
    ans = (ans - n + MOD) % MOD;
    ans = ans * inv(2) % MOD;
    cout << ans;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45775438/article/details/129937159