码迷,mamicode.com
首页 > 其他好文 > 详细

AtCoder AGC038 C-LCMs 题解

时间:2019-10-12 01:35:43      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:inline   个数   解决   false   复杂度   math   span   als   ace   

题目链接https://agc038.contest.atcoder.jp/tasks/agc038_c?lang=en

题意:给定一个数组,求这个数组中所有数对的LCM之和。

分析:网上看到了很多反演的解法,但是本题也可以通过埃氏筛在\(O(nlnlnn)\)的复杂度下解决。大致做法就是根据\(a_i \leq 1000000\),我们得到\(gcd(a_i, a_j) \leq 1000000\),于是可以通过枚举gcd来解决本题。实现参考代码,埃氏筛的思路就是求出gcd的值在\([1, 1000000]\)范围内的所有\(pair<a_i, a_j>\)的乘积之和,并去重,最后每项再乘逆元即可。

AC代码

#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define SIZE 1000100
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define int long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
const int mod = 998244353;
int n, inv[SIZE] = { 0,1 }, cnt[SIZE], tp, maxx = 0, ans[SIZE], res = 0;
signed main() {
    io(); cin >> n;
    rep(i, 1, n) {
        cin >> tp;
        cnt[tp]++;
        maxx = max(maxx, tp);
    }
    rep(i, 2, maxx) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    for (int i = maxx; i; --i) {    //求出gcd为i的所有pair的乘积之和
        int s1 = 0, s2 = 0;
        for (int j = i; j <= maxx; j += i) {
            s1 = (s1 + cnt[j] * j % mod) % mod;
            s2 = (s2 + cnt[j] * j % mod * j % mod) % mod;
        }
        ans[i] = (s1 * s1 % mod - s2 + mod) % mod;
        // s1 - s2 的作用是使得gcd为j的pair对数为 cnt * (cnt - 1)
        for (int j = i + i; j <= maxx; j += i) {
            ans[i] = (ans[i] - ans[j] + mod) % mod;
            //去重,删除gcd为ik (k > 1)的pair
        }
    }
    rep(i, 1, maxx) {   //计算 ans[i] / i % mod
        res = (res + ans[i] * inv[i] % mod) % mod;
    }
    cout << res * inv[2] % mod; //枚举了两遍gcd,res / 2
}

AtCoder AGC038 C-LCMs 题解

标签:inline   个数   解决   false   复杂度   math   span   als   ace   

原文地址:https://www.cnblogs.com/st1vdy/p/11657726.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!