ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

COMPFEST 13 Finals Online Mirror, cf-1575G. GCD Festival 题解

2021-11-15 18:34:07  阅读:169  来源: 互联网

标签:phi land GCD cdot 题解 sum 13 枚举 aligned



title: 'codeforces-COMPFEST 13 Finals Online Mirror, cf-1575G. GCD Festival'
date: 2021-11-15 17:04:50
tags: [math, number theory]
mathjax: true

题意

给定一个n长度的数组a,要你计算

\[\sum_{i=1}^{n} {\sum_{j=1}^{n} {\gcd(a_i, a_j) \cdot \gcd(i, j)}} \]

思路

莫比乌斯反演(其实我觉得这里叫欧拉反演更合适些)

\[gcd(i,j) = \sum _{d|i \land d|j} \phi(d) \]

代入原式

\[Ans=\sum_{i=1}^{n} {\sum_{j=1}^{n} {\gcd(a_i, a_j) \cdot \sum _{d|i \land d|j} \phi(d)}} \]

这里更换贡献计算顺序,枚举d来叠加答案的贡献

不过,在此之前,我们先约定一个符号

\[\sum_{i=d,i+=d}^{n} f(d) \]

\(i=d\) 表示 \(i\) 的初始值 \(i+=d\) 表示 \(i\) 的步长(每次\(+d\)),上面那个 \(n\) 表示循环上界(\(i\leq n\)),相当于for(int i=d;i<=n;i+=d)

下面继续计算答案

\[\begin{aligned} Ans&=\sum _{i=1}^{n} {\sum _{j=1}^{n} {\gcd(a_i, a_j) \cdot \sum _{d|i \land d|j} \phi(d)}} \\ &=\sum _{d=0}^{n} \phi(d) \sum _{i=d,i+=d}^{n}\sum _{j=d,j+=d}^{n}\gcd(a_i,a_j) \\ &=\sum _{d=0}^{n} \phi(d) \sum _{i=d,i+=d}^{n}\sum _{j=d,j+=d}^{n}\sum _{x|a_i \land x|a_j} \phi(x) \\ \end{aligned} \]

同理,我们枚举因子 \(x\),考虑什么时候\(a_i,a_j\)对答案有贡献

\[\begin{aligned} Ans&=\sum_{d=0}^{n} \phi(d) \sum _{i=d,i+=d}^{n}\sum _{j=d,j+=d}^{n}\sum _{x|a_i \land x|a_j} \phi(x) \\ &=\sum_{d=0}^{n} \phi(d) \sum _x \sum _{i=d,i+=d}^{n}\sum _{j=d,j+=d}^{n} [x|a_i\land x|a_j] \end{aligned} \]

其中,\(\sum _{i=d,i+=d}^{n}\sum _{j=d,j+=d}^{n} [x|a_i\land x|a_j]\) 表示当 \(x\) 整除 \(a_i\) 且 \(x\) 整除 \(a_j\) 时,有1个贡献。那么我们就可以统计数组 \(a\) 中能被 \(x\) 整除的数有多少个,求平方(组合数学中的乘法原理)即是 \(x\) 当前带来的贡献

公式推导如下

个人感觉写的有点赘余,每一步都只有一小步的化简,但是考虑到数学公式的难以理解,还是写的很冗长,还望和我一样的初学者看的更明白些

\[\begin{aligned} Ans&=\sum_{d=0}^{n} \phi(d) \sum _x \sum _{i=d,i+=d}^{n}\sum _{j=d,j+=d}^{n} [x|a_i\land x|a_j] \\ &=\sum_{d=0}^{n} \phi(d) \sum _x (\sum _{i=d,i+=d}^{n}[x|a_i] \cdot \sum _{j=d,j+=d}^{n} [x|a_j]) \\ &=\sum_{d=0}^{n} \phi(d) \sum _x (\sum _{i=d,i+=d}^{n}[x|a_i] \cdot \sum _{i=d,i+=d}^{n} [x|a_i]) \\ &=\sum_{d=0}^{n} \phi(d) \sum _x (\sum _{i=d,i+=d}^{n}[x|a_i])^2 \end{aligned} \]

好了,到这里,我们就可以考虑如何枚举 \(x\) 了,显然枚举到 \(n\) 不太实际(复杂度\(O(n^2)\)),我们考虑转而枚举每个元素的因子,这样的话就是 \(O(n\cdot log\ n \cdot max(|d(a_i)|)\) ,其中\(n\)来自于枚举 \(d\) ,\(log\ n\)来自于每次d枚举过程中选择的数(相关证明类似埃氏筛,与log的级数有关),\(|d(a_i)|\) 表示 \(a_i\) 的因子个数,也就是再去枚举每个数的因子(事先需要进行一次埃氏筛),因子个数大概也是log级别,这里由于知识面的不广暂不给出相关证明

代码

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

const i64 MOD = 1e9+7;
const int MX = 1e5+6;

vector<int> ph(MX);
vector<int> d[MX];

void get_phi() {
    for(int i=0;i<MX;++i) {
        ph[i] = i;
    }
    for(int i=2;i<MX;++i) {
        if(ph[i]==i)
            for(int j=i;j<MX;j+=i) {
                ph[j] -= ph[j]/i;
            }
    }

}
void get_divisor() {
    for(int i=1;i<MX;++i) {
        for(int j=i;j<MX;j+=i) {
            d[j].push_back(i);
        }
    }
}

int main(int argc, char const *argv[])
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);

    get_phi();
    get_divisor();

    int n;
    cin >> n;
    vector<i64> a(n+1);
    for(int i=1;i<=n;++i) {
        cin >> a[i];
    }

    i64 ans = 0;
    vector<int> cnt(MX);
    for(int i=1;i<=n;++i) {
        i64 s1=0;

        for(int j=i;j<=n;j+=i) {
            for(int e : d[a[j]]) {
                ++cnt[e];
            }
        }

        for(int j=i;j<=n;j+=i) {
            for(int e : d[a[j]]) {
                if(cnt[e]) {
                    i64 s2=cnt[e];
                    cnt[e] = 0;
                    s2 *= s2;
                    s2 %= MOD;
                    s2 *= ph[e];
                    s2 %= MOD;

                    s1 += s2;
                    s1 %= MOD;
                }
            }
        }

        ans += ph[i] * s1;
        ans %= MOD;
    }
    cout << ans;

    return 0;
}

标签:phi,land,GCD,cdot,题解,sum,13,枚举,aligned
来源: https://www.cnblogs.com/LacLic/p/15557637.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有