CF1900D Small GCD
这是一个需要欧拉反演的题目
首先,可以知道只和数字之间的大小有关,数列的顺序无关,那么就可以首先排一个序方便解决该问题。
根据欧拉函数的性质,知道
那么我们每次先确定中间的数,然后根据公式,得他它得贡献是
用欧拉函数处理一下这个东西后面的,然后得到
交换一下求和的顺序,得到,显然的,后面就是这个因数的出现次数
所以可以化简为
这个东西就可以很快的求出来了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<ctime>
#include<bitset>
#define int long long
using namespace std;
int phi[100005];
int not_prime[100005];
int prime[100005];
int p;
int a[100001];
long long ans;
void Eul(){
phi[1]=1;
not_prime[1]=0;
for(int i=2;i<=100000;++i){
if(!not_prime[i]){
prime[++p]=i;
phi[i]=i-1;
}
for(int j=1;j<=p&&i*prime[j]<=100000;++j){
not_prime[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
int t;
int n;
int cnt[100005];
signed main(){
Eul();
scanf("%lld",&t);
while(t--){
memset(cnt,0,sizeof(cnt));
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
sort(a+1,a+n+1);
ans=0;
for(int i=1;i<=n;++i){
long long tem=0;
for(int j=1;j*j<=a[i];j++){
if(a[i]%j!=0) continue;
tem+=phi[j]*cnt[j];
cnt[j]++;
if(j*j!=a[i]){
tem+=phi[a[i]/j]*cnt[a[i]/j];
cnt[a[i]/j]++;
}
}
ans+=tem*(n-i);
}
printf("%lld\n",ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2020-12-12 P2911 [USACO08OCT]Bovine Bones G(py)
2020-12-12 P1614 爱与愁的心痛(py)