Codeforces Round 911 (Div. 2) D. Small GCD
题目链接:https://codeforces.com/contest/1900/problem/D
对于已经排序好的数组 ,我们需要计算:
由于 ,因此:
代入可得:
因此,枚举到 时,遍历它的每个因数 ,看之前有多少个 有因数 ,乘上 即可。
求多个数欧拉函数的方法有很多,可以用埃筛或者线性筛。
埃筛递推思路:对于每个质数 ,把它的倍数都乘上 即可。
线性筛递推思路,对于质数 有:
- 若 是 的因子,但 不是 的因子,那么
- 若 是 的因子,并且 也是 的因子,那么
那么,如果用上 这条结论,可以得出 。这样也可以在 的复杂度来求欧拉函数,并且代码更好记也更好写。
除此以外,由于 以内的数字最多有 128 个因数,因此可以先遍历存下所有数字的因数。总体时间复杂度为 。
#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(); } }
注:转载请注明出处
本文作者:kpole
本文链接:https://www.cnblogs.com/1625--H/p/17860768.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步