AtCoder AGC038 C-LCMs 题解

题目链接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
}

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

时间: 2024-08-30 17:51:08

AtCoder AGC038 C-LCMs 题解的相关文章

AtCoder Beginner Contest 154 题解

人生第一场 AtCoder,纪念一下 话说年后的 AtCoder 比赛怎么这么少啊(大雾 AtCoder Beginner Contest 154 题解 A - Remaining Balls We have A balls with the string S written on each of them and B balls with the string T written on each of them. From these balls, Takahashi chooses one

AtCoder Beginner Contest 115 题解

题目链接:https://abc115.contest.atcoder.jp/ A Christmas Eve Eve Eve 题目: Time limit : 2sec / Memory limit : 1024MB Score : 100 points Problem Statement In some other world, today is December D-th. Write a program that prints Christmas if D=25, Christmas E

【ATcoder】AtCoder Beginner Contest 161 题解

题目链接:AtCoder Beginner Contest 161 原版题解链接:传送门 A - ABC Swap 这题太水,直接模拟即可. 1 #include <iostream> 2 using namespace std; 3 int main() { 4 int a, b, c; 5 cin >> a >> b >> c; 6 swap(a, b); 7 swap(a, c); 8 cout << a << " &

【AtCoder】ARC096 C-F题解

听说日本题思维都很棒,去涨涨智商qwq C - Half and Half 题解 枚举买多少个AB披萨也行 但是关于买x个AB披萨最后的总花费是个单峰函数,可以三分 这题有点像六省联考2017D1T1送分题期末考试 代码 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define MAXN 100005 #define PLI pair<lo

【AtCoder】AGC023 A-F题解

可以说是第一场AGC了,做了三道题之后还有30min,杠了一下D题发现杠不出来,三题滚粗了 rating起步1300+,感觉还是很菜... 只有三题水平显然以后还会疯狂--啊(CF的惨痛经历) 改题的感觉似乎还不错因为思维都非常的妙(我根本想不到) A - Zero-Sum Ranges 开场娱乐大家的小水题,区间和为0的情况存在于sum[R] == sum[L - 1],只要记录一下某一个值的sum出现了多少次就行,懒得离散化直接用map就OK啊 代码 #include <iostream>

AtCoder Beginner Contest 121 题解

题目链接:https://atcoder.jp/contests/abc121 A White Cells 分析:题目数据规模很小,直接暴力修改都可以.或者可以推出公式. 代码: 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int a[25][25] = {0}; 9 int H, W, h, w; 10 scanf("%d %d"

AtCoder Grand Contest 007题解

传送门 \(A\) 咕咕咕 //quming #include<bits/stdc++.h> #define R register #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) template<

AtCoder Grand Contest 008题解

传送门 \(A\) 分类讨论就行了 然而我竟然有一种讨论不动的感觉 int x,y; inline int min(R int x,R int y){return x<y?x:y;} inline int min(R int a,R int b,R int c,R int d){ return min(min(a,b),min(c,d)); } inline int calc(R int x,R int y){return y>=x?y-x:x-y+2;} int main(){ scanf(

AtCoder Grand Contest 014题解

传送门 \(A\) 首先大力猜测一下答案不会很大,所以次数大于\(10^6\)输出\(-1\)就行了 不过我并不会证上界,据说是因为如果\(a=b=c\)且都是偶数肯定\(-1\),否则设\(a\leq b\leq c\),则最大最小值的差为\(c-a\),一次操作之后变成了\({c-a\over 2}\),所以操作次数就是\(\log\)级别的了 typedef long long ll; ll a,b,c,sum;int res; int main(){ scanf("%lld%lld%ll