UVA11424 GCD - Extreme (I)[数论]

其实这题我也没太明白。。。

我们要求
\[ \sum_{i=1}^{N-1}\sum_{j=i+1}^Ngcd(i,j) \]
引理:

我们要求\(gcd(i,j)=k\)的个数,可转化为求\(gcd(i/k,j/k)=1\)的个数,即\(\varphi(N/k)\)

那么如果要求所有满足\(gcd(i,j)=k\)的和,即求\(\varphi(N/k)*k\)


为了满足10000组询问的复杂度,我们需要对这个式子做一些手脚。

\(f(n)=gcd(1,n)+gcd(2,n)+\cdots+gcd(n-1,n)\)

则最终答案\(ans(n)=f(2)+f(3)+\cdots+f(n)\)

难点在如何求\(f(n)\),前面提到,对于一个\(gcd(i,n)=k\),它对\(f(n)\)的贡献是\(\varphi(n/k)*k\)

于是如果我们枚举\(k\),把所有\(f(n)\)算出来,复杂度就到了\(O(n^2)\),显然不可行。

然而实际上,对于一个\(gcd(i,n)=k\),有\(k\mid n\),那么
\[ f(n)=\sum_{k\mid n}k*\varphi(n/k) \]

求完\(f(n)\)后,计算\(ans(n)\),实际上就相当于算了一个前缀和,询问的时候直接输出就得了。

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 4000010
#define MOD 2520
#define E 1e-12
#define ll long long
using namespace std;
inline int read()
{
    int f=1,x=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
ll n,phi[N],p[N],cnt,v[N],sum[N],s[N];
inline void init(int n)
{
    phi[1]=1;
    for(int i=2;i<=n;++i){
        if(!v[i]){phi[i]=i-1;p[++cnt]=i;}
        for(int j=1;j<=cnt;++j){
            if(p[j]>n/i) break;
            v[i*p[j]]=1;
            if(i%p[j]==0){
                phi[i*p[j]]=phi[i]*p[j];break;
            }
            phi[i*p[j]]=phi[i]*(p[j]-1);
        }
    }
    for(int i=1;i<n;++i)
        for(int j=i+i;j<n;j+=i){
            sum[j]+=i*phi[j/i];
        }
    for(int i=1;i<=n;++i) sum[i]+=sum[i-1];
}
int main()
{
    init(N);
    while(~scanf("%d",&n)&&n!=0){
        cout<<sum[n]<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/DarkValkyrie/p/11755263.html