首页 > 其他分享 >Codeforces Round 911 (Div. 2) D. Small GCD

Codeforces Round 911 (Div. 2) D. Small GCD

时间:2023-11-27 22:56:07浏览次数:31  
标签:phi psi GCD int sum Codeforces cdot vector Small

题目链接:https://codeforces.com/contest/1900/problem/D

对于已经排序好的数组 \(a\),我们需要计算:

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

由于 \(\sum_{d|n} \phi(d) = n\),因此:

\[\gcd(a_i, a_j) = \sum_{d|a_i, d|a_j} \psi(d) \]

代入可得:

\[\sum_{i=1}^n\sum_{j=i+1}^n\sum_{d|a_i, d|a_j} \psi(d) \cdot (n - j) \]

因此,枚举到 \(a_j\) 时,遍历它的每个因数 \(d\),看之前有多少个 \(a_i\) 有因数 \(d\),乘上 \(\psi(d) \cdot (n-j)\) 即可。

求多个数欧拉函数的方法有很多,可以用埃筛或者线性筛。

埃筛递推思路:对于每个质数 \(p\),把它的倍数都乘上 \((p - 1) / p\) 即可。

线性筛递推思路,对于质数 \(p\) 有:

  • 若 \(p\) 是 \(n\) 的因子,但 \(p^2\) 不是 \(n\) 的因子,那么 \(\psi(n) = \psi(n / p) \cdot p\)
  • 若 \(p\) 是 \(n\) 的因子,并且 \(p^2\) 也是 \(n\) 的因子,那么 \(\psi(n) = \psi(n / p) \cdot (p - 1)\)

那么,如果用上 \(\sum_{d|n} \phi(d) = n\) 这条结论,可以得出 \(\psi(n) = n - \sum_{d|n,d\neq n} \psi(d)\)。这样也可以在 \(O(n\log n)\) 的复杂度来求欧拉函数,并且代码更好记也更好写。

除此以外,由于 \(10^5\) 以内的数字最多有 128 个因数,因此可以先遍历存下所有数字的因数。总体时间复杂度为 \(O(m\log m)\)。

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

vector<int> phi;
vector<vector<int>> fac;

vector<int> getPhi(int n) {
  vector<int> f(n + 1);
  for (int i = 1; i <= n; i++) {
    f[i] = i;
  }
  for (int i = 1; i <= n; i++) {
    fac[i].push_back(i);
    for (int j = 2 * i; j <= n; j += i) {
      f[j] -= f[i];
      fac[j].push_back(i);
    }
  }
  return f;
}

vector<int> getPhi1(int n) {
  vector<int> f(n + 1);
  for (int i = 1; i <= n; i++) {
    f[i] = i;
    fac[i].push_back(1);
  }
  for (int i = 2; i <= n; i++) {
    if (f[i] == i) {
      for (int j = i; j <= n; j += i) {
        f[j] = f[j] / i * (i - 1);
      }
    }
    for (int j = i; j <= n; j += i) {
      fac[j].push_back(i);
    }
  }
  return f;
}

void solve() {
  int n;
  cin >> n;
  vector<int> a(n);
  for (int i = 0; i < n; i++) {
    cin >> a[i];
  }
  sort(a.begin(), a.end());
  unordered_map<int, int> mp;
  ll res = 0;
  for (int i = 0; i < n; i++) {
    for (int x : fac[a[i]]) {
      res += 1ll * mp[x] * phi[x] * (n - i - 1);
      mp[x]++;
    }
  }
  cout << res << "\n";
}

int main(){
  ios::sync_with_stdio(false); cin.tie(nullptr);
  int T;
  cin >> T;
  int n = 1e5;
  fac.resize(n + 1);
  phi = getPhi(n);
  while (T--) {
    solve();
  }
}

标签:phi,psi,GCD,int,sum,Codeforces,cdot,vector,Small
From: https://www.cnblogs.com/1625--H/p/17860768.html

相关文章

  • CodeforcesDS1
    CodeforcesDS1CF387EGeorgeandCards(2200)Problem给出一个\(1\)到\(n\)的排列(输入中的数组\(p\)),并给出一个长为\(k\)的数组\(b\),要求从\(p\)中删去\(n-k\)个元素后得到数组\(b\)。删除操作的定义:选取一个区间\([l,r]\),删去其中最小的元素,并获得\(r-l......
  • CodeforcesDP1
    CodeforcesDP1CF833BTheBakery(2200)Problem将一个长度为\(n\)的序列\(a\)分为\(k\)段,使得总价值最大。一段区间的价值表示为区间内不同数字的个数。\(n\leq35000,k\leqmin(n,50),1\lea_i\len\)。Solution记\(f_{i,l,j}\)表示考虑前\(i\)个数,划分成\(......
  • Codeforces Round 911 (Div. 2) D
    D.SmallGCD题意给定数组\(a\),求出数组\(a\)中所有三元组中较小的两个元素的\(gcd\)的和.分析显然数组中元素的顺序不影响统计答案,为了方便先将数组排个序;枚举中间的元素\(a_j\),那么只有它前边的元素能与其产生贡献,它后边的元素个数就是这个贡献的倍数,下面考虑枚......
  • Codeforces Round 911 (Div. 2)
    CodeforcesRound911(Div.2)A-CoverinWater解题思路:如果存在三个以上相邻的格子需要填,那么答案为二,否则有多少空格答案为多少。代码:#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;typedefpair<int,int>pii;#definefifirst#definese......
  • CF1900 D Small GCD 题解
    LinkCF1900DSmallGCDQuestion定义\(f(x,y,z)=\gcd(a,b)\),其中\(a,b\)为\(x,y,z\)中较小的那两个数给出数组\(a\),求\[\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n\sum\limits_{k=j+1}^nf(a_i,a_j,a_k)\]三个求和符号本质上就是选数组\(a\)中的三个数,也就是说,数......
  • D. Small GCD
    D.SmallGCDLet$a$,$b$,and$c$beintegers.Wedefinefunction$f(a,b,c)$asfollows:Orderthenumbers$a$,$b$,$c$insuchawaythat$a\leb\lec$.Thenreturn$\gcd(a,b)$,where$\gcd(a,b)$denotesthegreatestcommondivisor(GCD)ofi......
  • ORA-06502: PL/SQL: 数字或值错误:character string buffer too small
    原因是:DBMS_LOB.SUBSTR(CLOB)报错:超过缓存区长度解决办法:1、将自定义函数中的字符数参数设置为更大的数字(最大32767)。注意,这一设置和Oracle的版本有关系(Oracle10最大为4000,Oracle12可达32767)2、如果是拼接的字段来源是子表,那么就不在原sql中查对应字段,而是在后台JAVA中......
  • Codeforces Round 911 (Div. 2) A-C
    CodeforcesRound911(Div.2)A.CoverinWater题意:有n个单元格,有的空着有的被堵住,可以做两种操作:给一个空着的单元格放入水;将单元格的水移到另一个单元格。并且,若一个单元格左右两边都有水,它也会自动充满水。所有空着的单元格都要充满水,求最少的放入水的次数思路:若存在三......
  • Codeforces Round 911 (Div. 2)
    A-CoverinWater三个连续的.就可以造出无限水,这时直接输出\(2\),否则输出区间长度和。SubmissionB-LauraandOperations每次操作不会改变不需要的两个数的个数的和的奇偶性,而当这个和为偶数的时候,通过若干操作一定可以全部变成另一个。SubmissionC-Anji'sBinary......
  • Codeforces Round 911 (Div. 2) A
    真的太菜了……题目链接:Problem-A-Codeforces//Problem:A.CoverinWater//Contest:Codeforces-CodeforcesRound911(Div.2)//URL:https://codeforces.com/contest/1900/problem/0#//MemoryLimit:256MB//TimeLimit:1000ms////PoweredbyCPEd......