Codeforces Round 911 (Div. 2) D. Small GCD
D. Small GCD
题意
给定数组 ,求出数组 中所有三元组中较小的两个元素的 的和.
分析
显然数组中元素的顺序不影响统计答案,为了方便先将数组排个序;
枚举中间的元素 ,那么只有它前边的元素能与其产生贡献,它后边的元素个数就是这个贡献的倍数,下面考虑枚举中间元素时的贡献
所求即为 , 无论怎样的暴力都是 的。
赛时没想出来优化,赛后看了别人代码才想到欧拉反演。
欧拉反演公式:
证明欧拉反演的话只要证明因子的的欧拉函数之和是一个积性函数就能顺利整出来。
有了上述结论,原式子可以转为
已经是一个易处理的柿子,考虑实现细节
从前往后枚举元素,假设已经处理到了 ,枚举因子 ,如果前面 个元素中已经出现了 次因子 ,那么这一位的贡献直接加上 , 同时++cnt;
最后给每一位贡献乘上系数即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL),cout.tie(NULL)
const int N = 1e5 + 7;
int phi[N];
void init(int n){
for (int i(1); i <= n; ++i) phi[i] = i;
for (int i(1); i <= n; ++i)
for (int j(2 * i); j <= n; j += i)
phi[j] -= phi[i];
}
void doit(){
int n; cin >> n;
vector<int> a(n + 1), cnt(N);
for (int i(1); i <= n; ++i) cin >> a[i];
sort(a.begin() + 1, a.end());
ll ans = 0;
for (int i(1); i <= n; ++i){
int x = a[i];
ll res = 0;
for (int j(1); j * j <= x; ++j){
if (x % j) continue;
res += 1ll * phi[j] * cnt[j]++;
if (j * j != x) res += 1ll * phi[x / j] * cnt[x / j]++;
}
ans += res * (n - i);
}
cout << ans << '\n';
}
int main(){
IOS;
//freopen("in.txt", "r", stdin);
int T = 1; cin >> T;
init(N);
while (T--){
doit();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2022-11-27 CF1119E Pavel and Triangles 题解