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

Codeforces Round 911 (Div. 2) D

时间:2023-11-28 20:44:06浏览次数:38  
标签:cnt gcd limits sum Codeforces varphi Div 911 欧拉

Codeforces Round 911 (Div. 2) D

D. Small GCD

题意

定义\(f(a,b,c)\)为\(a,b,c\)中较小两个数的\(gcd\),给定数组\(a_{1...n}\),求\(\sum\limits_{i=1}^{n}\sum\limits_{j=i+1}^{n}\sum\limits_{k=j+1}^{n}f(a_i,a_j,a_k)\)

题解

显然可以先排序,不会影响结果,排完序后\(a_k\)就是最大的,不会对\(gcd(a_i,a_j)\)产生影响.

所以当我们去枚举中间的\(a_j\)时,那么对于\(a_j\)来说,产生\((n-j)\times \sum\limits_{i = 1}^{n-1}gcd(a_i,a_j)\),其中\((n-j)\)是因为后面的\((n-j)\)个\(a_k\)都不会对\(gcd(a_i,a_j)\)产生影响,所以答案最终就是\(\sum\limits_{i=1}^{n-2}\sum\limits_{j=i+1}^{n-1}gcd(a_i,a_j) \times (n-j)\),而这样做的复杂度是\(O(n^2logm)\),其中\(m\)是\(\max\limits_{1\leq i\leq n}\{a_i\}\),而这样是会超时的.

到了这里,就该推出今天刚了解的欧拉反演了!

欧拉反演:即\(n\)的所有因子的欧拉函数和为n.

​ \(\sum\limits_{d|n}\varphi(d)=n\).

将\(n\)换成其他:

​ \(gcd(i,j) = \sum\limits_{d|gcd(i,j)}\varphi(d) = \sum\limits_{d|i}\sum\limits_{d|j}\varphi(d)\)

则:

​ \(\sum\limits_{i=1}^{n}gcd(i,n) = \sum\limits_{i=1}^{n}\sum\limits_{d|i}\sum\limits_{d|n}\varphi(d)=\sum\limits_{d|n}\sum\limits_{i=1}^{n}\sum\limits_{d|i}\varphi(d)=\sum\limits_{d|n}\frac{n}{d}\varphi(d)\)

即:

​ \(\sum\limits_{i=1}^{n}gcd(i,n)=\sum\limits_{d|n}\frac{n}{d}\varphi(d)\)

因为\(1\sim n\)里面含有因子为\(d\)一共有\(\frac{n}{d}\)个,所以这里就直接替换了,不过在这题里面从\(a_1 \sim a_{j-1}\)里面并不知道含有\(d\)作为因子数的有多少,所以我们需要维护\(a_1 \sim a_{j-1}\)中每个数的所有因子的个数\(cnt_d\),那么要计算\(1 \sim j-1\)的\(gcd\)则可以替换成:

​ \(\sum\limits_{i=1}^{j-1}gcd(a_i,a_j) = \sum\limits_{d|a_j}cnt_d\varphi(d)\)

对于每一个数,先预处理出所含的约数,然后维护\(cnt_d\),就可以直接利用公式求和了.

ACcode:

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

vector<int> euler_range(int n) {
	vector<int> phi(n + 1), prime;
	vector<bool> is_prime(n + 1, true);
	is_prime[1] = 0, phi[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (is_prime[i]) prime.push_back(i), phi[i] = i - 1;
		for (int j = 0; j < (int)prime.size() && i * prime[j] <= n; j++) {
			is_prime[i * prime[j]] = 0;
			if (i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
			else {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
		}
	}
	return phi;
};

constexpr int N = 1E5;

auto phi = euler_range(N);
vector<int> fac[N + 1];

void solve() {

	int n;
	cin >> n;
	vector<i64> a(n), b;
	for (auto &i : a) cin >> i;
	ranges::sort(a);
	i64 ans = 0;
	vector<int> cnt(N + 1);
	for (int j = 0; j < n; j ++) {
		for (auto d : fac[a[j]])
			ans += 1ll * phi[d] * (n - j - 1) * cnt[d];
		for (auto d : fac[a[j]])
			cnt[d] ++;
	}

	cout << ans << '\n';

}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	for (int i = 1; i <= N; i ++)
		for (int j = 1; j <= N / i; j ++)
			fac[i * j].push_back(i);

	int T;
	cin >> T;
	while (T--) {
		solve();
	}

	return 0;
}

参考资料:

欧拉反演 欧拉定理 - emptyset - 洛谷博客 (luogu.com.cn)

欧拉函数|(扩展)欧拉定理|欧拉反演 - Morning_Glory - 博客园 (cnblogs.com)

Codeforces Round 911 (Div. 2) A-E - 知乎 (zhihu.com)

标签:cnt,gcd,limits,sum,Codeforces,varphi,Div,911,欧拉
From: https://www.cnblogs.com/Kescholar/p/17863020.html

相关文章

  • CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)
    CodeTONRound7(Div.1+Div.2,Rated,Prizes!)A-JaggedSwaps思路:a2到an的数只要相邻为逆序都可以交换,只需要判断a1是否为1即可#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong//#defineint__int128#definedoublelongdoubletypedefpai......
  • Codeforces Round 903 (Div. 3)
    CodeforcesRound903(Div.3)A.Don'tTrytoCount大概题意给你两个字符串a,b。a串可进行的操作为将整个a串复制到之前的a串后面(直接用a+a即可),然后看操作多少次可以让b串变为a串的子串如果不能就输出-1。#include<iostream>usingnamespacestd;stringa,b;voidsolve()......
  • Codeforces Round 894 (Div. 3)
    CodeforcesRound894(Div.3)A.GiftCarpet题意:判断一列一个字母有没有“vika”思路:挨个枚举每一列#include<bits/stdc++.h>usingnamespacestd;charmp[25][25];charx[]={'v','i','k','a'};voidsolve(){intm,n;cin>>......
  • Codeforces Round 911 (Div. 2) D. Small GCD
    题目链接:https://codeforces.com/contest/1900/problem/D对于已经排序好的数组\(a\),我们需要计算:\[\sum_{i=1}^n\sum_{j=i+1}^ngcd(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\su......
  • 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......
  • Codeforces Round 911 (Div. 2) A-C
    CodeforcesRound911(Div.2)A.CoverinWater题意:有n个单元格,有的空着有的被堵住,可以做两种操作:给一个空着的单元格放入水;将单元格的水移到另一个单元格。并且,若一个单元格左右两边都有水,它也会自动充满水。所有空着的单元格都要充满水,求最少的放入水的次数思路:若存在三......
  • CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)
    20231127A.JaggedSwaps题意是:给你一个数组进行无数次的操作问你能不能单调思路:通过观察发现进行操作大的一定会被放在后面,所以一定会单调,但是操作是从2开始的,所以下表1的地方一定要是1usingnamespacestd;inta[20];voidsolve(){intn;cin>>n;for(in......