UVA 11426 GCD

来源:互联网 发布:淘宝店家如何开通花呗 编辑:程序博客网 时间:2024/06/17 15:34

解这道题,需要以下几步:

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<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<ctime>#include<iostream>#include<algorithm>#include<vector>#include<string>#include<queue>using namespace std;typedef long long ll;const int MAXN = 4000010;bool check[MAXN+10];int phi[MAXN+10];int prime[MAXN+10];int tot;void phi_and_prime_table(int N){    memset(check,false,sizeof(check));    phi[1] = 1;    tot = 0;    for(int i = 2; i <= N; i++)    {        if( !check[i] )        {            prime[tot++] = i;            phi[i] = i-1;        }        for(int j = 0; j < tot; j++)        {            if(i * prime[j] > N)break;            check[i * prime[j]] = true;            if( i % prime[j] == 0)            {                phi[i * prime[j]] = phi[i] * prime[j];                break;            }            else            {                phi[i * prime[j]] = phi[i] * (prime[j] - 1);            }        }    }}ll f[MAXN],s[MAXN];int main(){    phi_and_prime_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;}
0 0