51nod 1594 Gcd and Phi 莫比乌斯反演

本文介绍了一种利用数论反演技巧解决特定数学问题的方法。该问题要求计算从1到n范围内所有整数的欧拉函数值的两两最大公约数的欧拉函数之和。文章详细解释了如何通过枚举、换元、反演等步骤简化原始表达式,并给出了具体的实现代码。
摘要由CSDN通过智能技术生成

题意:
给出 n(n<=2106) n ( n <= 2 ∗ 10 6 ) ,求
ni=1nj=1ϕ(gcd(ϕ(i),ϕ(j))) ∑ i = 1 n ∑ j = 1 n ϕ ( g c d ( ϕ ( i ) , ϕ ( j ) ) ) 的值。

分析:
看到这种题显然想反演了。

ans=i=1nj=1nϕ(gcd(ϕ(i),ϕ(j))) a n s = ∑ i = 1 n ∑ j = 1 n ϕ ( g c d ( ϕ ( i ) , ϕ ( j ) ) )

=D=1nϕ(D)i=1nj=1n[gcd(ϕ(i),ϕ(j))==D] = ∑ D = 1 n ϕ ( D ) ∑ i = 1 n ∑ j = 1 n [ g c d ( ϕ ( i ) , ϕ ( j ) ) == D ]

然后我们枚举 ϕ(i) ϕ ( i ) ϕ(j) ϕ ( j ) ,我们设 ad=ni=1[ϕ(i)==d] a d = ∑ i = 1 n [ ϕ ( i ) == d ] x=phi(i) x = p h i ( i ) y=phi(j) y = p h i ( j ) ,其实可以理解为换元,则原式可以变为,
=D=1nϕ(D)x=1ny=1n[gcd(x,y)==D]axay = ∑ D = 1 n ϕ ( D ) ∑ x = 1 n ∑ y = 1 n [ g c d ( x , y ) == D ] ∗ a x ∗ a y

然后就是很显然的反演了,我们设 sumi=i|tat s u m i = ∑ i | t a t
=D=1nϕ(D)d=1nμ(d)(sumDd)2 = ∑ D = 1 n ϕ ( D ) ∑ d = 1 n μ ( d ) ∗ ( s u m D ∗ d ) 2

T=Dd T = D d ,则
=T=1n(sumT)2d|Tμ(d)ϕ(T/d) = ∑ T = 1 n ( s u m T ) 2 ∑ d | T μ ( d ) ∗ ϕ ( T / d )

f(i)=d|iμ(d)ϕ(i/d) f ( i ) = ∑ d | i μ ( d ) ∗ ϕ ( i / d ) ,是个狄利克雷卷积,一定是个积性函数,直接可以上线筛。对于 x=pk x = p k ,则 f(x)=ϕ(x)ϕ(x/p) f ( x ) = ϕ ( x ) − ϕ ( x / p ) 。这个 sum s u m 可以枚举倍数解决,复杂度 O(nlogn) O ( n l o g n ) 的。其实排序询问可以节约时间,不过暴力也可以过。直接强行清空跑 sum s u m 就好。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define LL long long

const int maxn=2e6+7;

using namespace std;

LL phi[maxn],f[maxn],sum[maxn],a[maxn];
LL not_prime[maxn],prime[maxn],low[maxn];
LL n,cnt,T;

void getf(LL n)
{
    phi[1]=1;
    f[1]=1; 
    for (LL i=2;i<=n;i++)
    {
        if (!not_prime[i])
        {
            prime[++cnt]=i;
            phi[i]=i-1;
            f[i]=phi[i]-phi[1];
            low[i]=i;
        }
        for (LL j=1;j<=cnt;j++)
        {
            if (i*prime[j]>n) break;
            not_prime[i*prime[j]]=1;
            if (low[i]%prime[j]==0) low[i*prime[j]]=low[i]*prime[j];
                               else low[i*prime[j]]=prime[j];
            if (i*prime[j]==low[i*prime[j]])
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                f[i*prime[j]]=phi[i*prime[j]]-phi[i];
            }
            else
            {
                LL x=low[i*prime[j]],y=i*prime[j]/x;
                f[i*prime[j]]=f[x]*f[y];
                phi[i*prime[j]]=phi[x]*phi[y];
            }
            if (i%prime[j]==0) break; 
        }
    }
}

int main()
{
    getf(2e6);  
    scanf("%lld",&T);   
    while (T--)
    {
        scanf("%lld",&n);
        LL ans=0;
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
        for (LL i=1;i<=n;i++) a[phi[i]]++;      
        for (LL i=1;i<=n;i++)
        {
           for (LL j=i;j<=n;j+=i) sum[i]+=a[j];
        }
        for (LL i=1;i<=n;i++) ans+=sum[i]*sum[i]*f[i];
        printf("%lld\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值