您的位置:首页 > 其它

UVa 11426题解 GCD - Extreme (II) 题解

2017-09-14 08:35 441 查看
…我怎么又在做水题

题目传送门

翻译:

这道题是说给一个n然后求所有满足1<=i<j<=n的数对(i,j),求他们的gcd之和

题解:

我们来推结论

我们要求的是gcd之和,如果我们把gcd(1,n),gcd(2,n),gcd(3,n)...gcd(n−1,n)的和命为f(n)

如果令S(n)为n对于题目中要求的答案,那么S(n)=f(1)+f(2)+...+f(n)

显然我们可以递推,S(n)=S(n−1)+f(n)

所以现在我们只需要求出f(n)

对于一个n,我们令g(n,i)表示和n的最大公约数为i的数有多少个

那么f(n)=∑ni=1i∗g(n,i)∗[i|n]

所以现在任务就是求g(n,i)

注意到gcd(x,n)==i的充要条件是gcd(xi,ni)==1

所以我们只需要去求和ni互质的数有多少个就可以了,对于一个i,和ni互质的有多少个数

就有多少个xi也就有多少个x

所以我们在对于每个i枚举的时候,都找i的倍数,使得i是n的因数,然后更新累加枚举的n的答案

然后先预处理一个欧拉函数值出来就可以了

欧拉筛筛素数求欧拉函数代码:

void get_phi(){
phi[1]=1;
for(register int i=2;i<=MAXN;i++){
if(!is_not_prime[i]){
prime[++prime[0]]=i;
phi[i]=i-1;
}
for(register int j=1;j<=prime[0]&&i*prime[j]<=MAXN;j++){
is_not_prime[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=prime[j]*phi[i];//important
break;
}else{
phi[i*prime[j]]=phi[i]*(prime[j]-1);//gcd(i,prime[j])==1
}//gcd(a,b)==1 -> phi[a*b]==phi[a]*phi[b]
}
}
}


完整代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=4000000;
long long S[MAXN+10],prime[MAXN],f[MAXN+10],phi[MAXN+10],is_not_prime[MAXN];
void get_phi(){
phi[1]=1;
for(register int i=2;i<=MAXN;i++){
if(!is_not_prime[i]){
prime[++prime[0]]=i;
phi[i]=i-1;
}
for(register int j=1;j<=prime[0]&&i*prime[j]<=MAXN;j++){
is_not_prime[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=prime[j]*phi[i];
break;
}else{
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
}
int main(){
get_phi();
for(register int i=1;i<=MAXN;i++)
for(register int n=i*2;n<=MAXN;n+=i) f
+=i*phi[n/i];
S[2]=f[2];
for(register int n=3;n<=MAXN;n++)S
=S[n-1]+f
;
int n;
while(scanf("%d",&n)==1&&n) printf("%lld\n",S
);
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: