【51nod】Gcd and Phi(反演)

基准时间限制:2 秒 空间限制:131072 KB 分值: 320
F(n)=ni=1nj=1ϕ(ϕi,ϕj) F ( n ) = ∑ i = 1 n ∑ j = 1 n ϕ ( ϕ i , ϕ j )
其中 ϕ 表示欧拉函数。欧拉函数ϕn 是不超过n的数中与n互质的数的数目。
ϕ(ϕi,ϕj) 表示i,j欧拉函数值的最大公约数的欧拉函数值.

给出n,求F(n)的值。
Input
一行,包含正整数T,表示数据组数。T<=5
接下来T行每行一个正整数n。n<=2*10^6
Output
共T行,每行包含一个答案。
Input示例
1
1
Output示例
1
思路:发现对于枚举的i是没有直接关系的,而是一个映射即 ϕ(i) ϕ ( i ) ,所以应该直接去枚举这个,所以我们设 g(x)ϕ(i) g ( x ) 为 有 多 少 ϕ ( i ) 等于 x x ,这个可以线性统计一下。
则转化为:

ans=i=1nj=1ng(i)g(j)ϕ(gcd(i,j))

接下来显然我们肯定要去枚举gcd的,所以:

=d=1nϕ(d)d|ind|jng(i)g(j)[gcd(i,j)=d]=d=1nϕ(d)i=1ndj=1ndg(id)g(jd)[gcd(i,j)=1] = ∑ d = 1 n ϕ ( d ) ∑ d | i n ∑ d | j n g ( i ) g ( j ) [ g c d ( i , j ) = d ] = ∑ d = 1 n ϕ ( d ) ∑ i = 1 n d ∑ j = 1 n d g ( i d ) g ( j d ) [ g c d ( i , j ) = 1 ]

这里就有可以引入莫比乌斯函数了:
=d=1nϕ(d)i=1ndj=1ndg(id)g(jd)k|gcd(i,j)μ(k)=d=1nϕ(d)i=1ndj=1ndg(id)g(jd)k|i,k|jμ(k)=d=1nϕ(d)k=1ndμ(k)i=1ndkj=1ndkg(idk)g(jdk) = ∑ d = 1 n ϕ ( d ) ∑ i = 1 n d ∑ j = 1 n d g ( i d ) g ( j d ) ∑ k | g c d ( i , j ) μ ( k ) = ∑ d = 1 n ϕ ( d ) ∑ i = 1 n d ∑ j = 1 n d g ( i d ) g ( j d ) ∑ k | i , k | j μ ( k ) = ∑ d = 1 n ϕ ( d ) ∑ k = 1 n d μ ( k ) ∑ i = 1 n d k ∑ j = 1 n d k g ( i d k ) g ( j d k )

然后就可以搞了。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ull  unsigned long long
#define ll long long
#define ul unsigned int
#define maxn 2000005
#define mod 1000000007
using namespace std;
bool isP[maxn];
int prime[maxn];
int mu[maxn];
int phi[maxn];
int cnt;
void init()
{
    phi[1]=mu[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(!isP[i])
        {
            prime[cnt++]=i;
            phi[i]=i-1;
            mu[i]=-1;
        }
        for(int j=0;j<cnt&&(ll)i*prime[j]<maxn;j++)
        {
            int now=i*prime[j];
            isP[now]=true;
            if(i%prime[j])
            {
                phi[now]=phi[i]*(prime[j]-1);
                mu[now]=-mu[i];
            }
            else
            {
                phi[now]=phi[i]*prime[j];
                mu[now]=0;
                break;
            }
        }
    }
}
int g[maxn];
ll G[maxn];
int n;
void _init()
{
    memset(g,0,sizeof(g));
    memset(G,0,sizeof(G));
    for(int i=1;i<=n;++i)
        ++g[phi[i]];
    for(int i=1;i<=n;++i)
        for(int j=i;j<=n;j+=i)
            G[i]+=g[j];
    for(int i=1;i<=n;i++)
        G[i]*=G[i];
}
int main()
{
    init();
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        _init();
        ll ans=0;
        for(int d=1;d<=n;d++)
        {
            int limit=n/d;
            for(int k=1;k<=limit;k++)
                if(mu[k])
                    ans+=mu[k]*G[k*d]*phi[d];
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值