【UVA 11426】 【求sum(gcd(i,j),1<=i<j<=n)1<n<4000001】

来源:互联网 发布:python 查看字节码 编辑:程序博客网 时间:2024/05/16 17:37
题意:

求sum(gcd(i,j),1<=i<j<=n)1<n<4000001

思路:

1.建立递推关系,s(n)=s(n-1)+gcd(1,n)+gcd(2,n)+……+gcd(n-1,n);

2.设f(n)=gcd(1,n)+gcd(2,n)+……+gcd(n-1,n)。

gcd(x,n)=i是n的约数(x<n),按照这个约数进行分类。设满足gcd(x,n)=i的约束有g(n,i)个,则有f(n)=sum(i*g(n,i))。

而gcd(x,n)=i等价于gcd(x/i,n/i)=1,因此g(n,i)等价于phi(n/i).phi(x)为欧拉函数。

3.降低时间复杂度。用筛法预处理phi[x]表

逆向思路用筛法预处理f(x)->枚举因数,更新其所有倍数求解。

代码:

#include <bits/stdc++.h>using  namespace  std;typedef long long ll;const int maxn=4100000;   ll f[maxn],s[maxn];ll phi[maxn];//储存结果void phi_table(int n){    memset(phi,0,sizeof(phi));    phi[1]=1;//首项为1    for(int i=2;i<=n;++i)if(!phi[i])//i必定为素数(类似筛素数法)    for(int j=i;j<=n;j+=i)//不断枚举i的倍数    {        if(!phi[j])phi[j]=j;//如果没有算过就初始化为j        phi[j]=phi[j]/i*(i-1);//进行计算    }}int  main(){    phi_table(maxn);    memset(f,0,sizeof(f));    for(int i=1;i<=maxn;i++)      for(int j=i+i;j<=maxn;j+=i)//最大公约数不能为本身      f[j]+=i*phi[j/i];      memset(s,0,sizeof(s));    s[1]=0;    for(int i=2;i<=maxn;i++)      s[i]=s[i-1]+f[i];      int n;    while(scanf("%d",&n),n){      printf("%lld\n",s[n]);    }    return 0;}



1 0
原创粉丝点击