51Nod1594 Gcd and Phi

本文通过一道编程竞赛题目介绍了如何利用扩展的欧几里得算法和莫比乌斯反演解决关于最大公约数和欧拉函数的问题。通过计算欧拉函数的积并反演,得出原问题的解答。文章展示了数论在算法中的应用,以及如何预处理和优化计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题目看这里
一个简单的反演题目:

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

首先做一下变换
ni=1nj=1ϕ(gcd(ϕ(i),ϕ(j))) ∑ i = 1 n ∑ j = 1 n ϕ ( g c d ( ϕ ( i ) , ϕ ( j ) ) )
=nd=1ϕ(d)f(d) = ∑ d = 1 n ϕ ( d ) ∗ f ( d )
这里 f(d)=i,j[gcd(ϕ(i),ϕ(j))=d] f ( d ) = ∑ i , j [ g c d ( ϕ ( i ) , ϕ ( j ) ) = d ]
表示有多少对i,j满足它们的 ϕ ϕ 值的最大公约数为d
我们令 F(d)=i,j[d|gcd(ϕ(i),ϕ(j))] F ( d ) = ∑ i , j [ d | g c d ( ϕ ( i ) , ϕ ( j ) ) ] ,就有 F(n)=n|df(d) F ( n ) = ∑ n | d f ( d )
反演得到 f(n)=dF(nd)μ(d) f ( n ) = ∑ d F ( n ∗ d ) ∗ μ ( d )
所以原式可以写成 ij<=nϕ(i)F(ij)μ(j) ∑ i ∗ j <= n ϕ ( i ) ∗ F ( i ∗ j ) ∗ μ ( j )
预处理 μ,ϕ μ , ϕ F F 的值就可以了

#pragma GCC optimize("O3")
#pragma G++ optimize("O3") # p r a g m a   G + +   o p t i m i z e ( " O 3 " )
#include<stdio.h> # i n c l u d e < s t d i o . h >
#include<string.h> # i n c l u d e < s t r i n g . h >
#include<algorithm> # i n c l u d e < a l g o r i t h m >
#define N 2000010  # d e f i n e   N   2000010  
#define LL long long # d e f i n e   L L   l o n g   l o n g
using namespace std; u s i n g   n a m e s p a c e   s t d ;
int n,T; long long S; i n t   n , T ;   l o n g   l o n g   S ;
int w[N>>2],t,phi[N],mu[N],vis[N],c[N]; i n t   w [ N >> 2 ] , t , p h i [ N ] , m u [ N ] , v i s [ N ] , c [ N ] ;
inline LL F(int x){ return (LL)c[x]c[x]; } i n l i n e   L L   F ( i n t   x ) {   r e t u r n   ( L L ) c [ x ] ∗ c [ x ] ;   }
inline void cal(){ i n l i n e   v o i d   c a l ( ) {
scanf("%d",&n); memset(c,S=0,sizeof c); s c a n f ( " % d " , & n ) ;   m e m s e t ( c , S = 0 , s i z e o f   c ) ;
for(int i=1;i<=n;++i) ++c[phi[i]]; f o r ( i n t   i = 1 ; i <= n ; + + i )   + + c [ p h i [ i ] ] ;
for(int i=1;i<=n;++i) f o r ( i n t   i = 1 ; i <= n ; + + i )
for(int j=i+i;j<=n;j+=i) c[i]+=c[j]; f o r ( i n t   j = i + i ; j <= n ; j + = i )   c [ i ] + = c [ j ] ;
for(int i=1;i<=n;++i) if(mu[i]) f o r ( i n t   i = 1 ; i <= n ; + + i )   i f ( m u [ i ] )
for(int j=1;ij<=n;++j) f o r ( i n t   j = 1 ; i ∗ j <= n ; + + j )
S+=(LL)F(ij)mu[i]phi[j]; S + = ( L L ) F ( i ∗ j ) ∗ m u [ i ] ∗ p h i [ j ] ;
printf("%lld",S); p r i n t f ( " % l l d " , S ) ;
} }
int main(){ i n t   m a i n ( ) {
phi[1]=mu[1]=1; p h i [ 1 ] = m u [ 1 ] = 1 ;
for(int i=2;i<=2000000;++i){ f o r ( i n t   i = 2 ; i <= 2000000 ; + + i ) {
if(!vis[i]){ mu[w[++t]=i]=1; phi[i]=i1; } i f ( ! v i s [ i ] ) {   m u [ w [ + + t ] = i ] = − 1 ;   p h i [ i ] = i − 1 ;   }
for(int j=1,k;(k=iw[j])<=2000000;++j){ f o r ( i n t   j = 1 , k ; ( k = i ∗ w [ j ] ) <= 2000000 ; + + j ) {
vis[k]=1; v i s [ k ] = 1 ;
if(i%w[j]==0){ phi[k]=phi[i]w[j]; mu[k]=0; break; } i f ( i % w [ j ] == 0 ) {   p h i [ k ] = p h i [ i ] ∗ w [ j ] ;   m u [ k ] = 0 ;   b r e a k ;   }
phi[k]=phi[i](w[j]1); mu[k]=mu[i]; p h i [ k ] = p h i [ i ] ∗ ( w [ j ] − 1 ) ;   m u [ k ] = − m u [ i ] ;
}  }  
} }
for(scanf("%d",&T);T;cal()); f o r ( s c a n f ( " % d " , & T ) ; T − − ; c a l ( ) ) ;
} }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值