#莫比乌斯反演,欧拉函数#BZOJ 4804 欧拉心算

题目

∑ i = 1 n ∑ j = 1 n φ ( g c d ( i , j ) ) \sum_{i=1}^n\sum_{j=1}^n\varphi(gcd(i,j)) i=1nj=1nφ(gcd(i,j))


分析

= ∑ d = 1 n φ ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ g c d ( i , j ) = = 1 ] =\sum_{d=1}^n\varphi(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,j)==1] =d=1nφ(d)i=1dnj=1dn[gcd(i,j)==1]
= ∑ d = 1 n φ ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ ∑ k ∣ i , k ∣ j μ ( k ) =\sum_{d=1}^n\varphi(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{k|i,k|j}\mu(k) =d=1nφ(d)i=1dnj=1dnki,kjμ(k)
= ∑ d = 1 n φ ( d ) ∑ k = 1 ⌊ n d ⌋ μ ( k ) ( ⌊ n k d ⌋ ) 2 =\sum_{d=1}^n\varphi(d)\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)(\lfloor\frac{n}{kd}\rfloor)^2 =d=1nφ(d)k=1dnμ(k)(kdn)2
枚举 i = k d i=kd i=kd可以得到 = ∑ i = 1 n ( ⌊ n i ⌋ ) 2 ∑ d ∣ i μ ( d ) φ ( i d ) =\sum_{i=1}^n(\lfloor\frac{n}{i}\rfloor)^2\sum_{d|i}\mu(d)\varphi(\frac{i}{d}) =i=1n(in)2diμ(d)φ(di)
后面预处理,详见代码,时间复杂度 O ( N + T ( n ) ) O(N+T\sqrt(n)) O(N+T( n))


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1e7+1; bool v[N];
int prime[N],cnt; long long dp[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(long long ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void init(){
	dp[1]=1;
	for (rr int i=2;i<N;++i){
		if (!v[i]) prime[++cnt]=i,dp[i]=i-2;
		for (rr int j=1;j<=cnt&&prime[j]*i<N;++j){
			v[i*prime[j]]=1;
			if (i%prime[j]==0){
				if (i/prime[j]%prime[j]==0) dp[i*prime[j]]=dp[i]*prime[j];//dp[i*prime[j]]含有指数超过2次的prime[j],所以不含或含1次prime[j]的莫比乌斯函数会被消掉,所以剩下的就是超过1次的欧拉函数,按照欧拉函数的方法是乘上prime[j]
				    else dp[i*prime[j]]=dp[i/prime[j]]*(prime[j]-1)*(prime[j]-1);//脑补一下
			    break;
			}
			dp[i*prime[j]]=dp[i]*dp[prime[j]];//狄利克雷卷积也是积性函数
		}
	}
	for (rr int i=2;i<N;++i) dp[i]+=dp[i-1];
} 
signed main(){
	init();
	for (rr int t=iut();t;--t){
		rr int n=iut(); rr long long ans=0;
		for (rr int l=1,r;l<=n;l=r+1)
			ans+=(dp[r=n/(n/l)]-dp[l-1])*(n/l)*(n/l);
		print(ans),putchar(10);
	}
	return 0;
} 

分析

然而此代码跑的很慢,然而如果推广到 n n n m m m就很实用,以下方法就废掉了,不过上面的好像也会废掉
= ∑ d = 1 n φ ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ g c d ( i , j ) = = 1 ] =\sum_{d=1}^n\varphi(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,j)==1] =d=1nφ(d)i=1dnj=1dn[gcd(i,j)==1]
其实这里就可以直接出结果了,根据洛谷 2158 仪仗队,可以知道答案是 ∑ d = 1 n φ ( d ) ( 2 φ ( ⌊ n d ⌋ ) − 1 ) \sum_{d=1}^n\varphi(d)(2\varphi(\lfloor\frac{n}{d}\rfloor)-1) d=1nφ(d)(2φ(dn)1)
时间复杂度相同,实测总时间少了1000ms


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1e7+1; int prime[N],cnt; long long phi[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(long long ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void init(){
	phi[1]=1;
	for (rr int i=2;i<N;++i){
		if (!phi[i]) prime[++cnt]=i,phi[i]=i-1;
		for (rr int j=1;j<=cnt&&prime[j]*i<N;++j){
			if (i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];
			    break;
			}
			phi[i*prime[j]]=phi[i]*(prime[j]-1); 
		}
	}
	for (rr int i=2;i<N;++i) phi[i]+=phi[i-1];
} 
signed main(){
	init();
	for (rr int t=iut();t;--t){
		rr int n=iut(); rr long long ans=0;
		for (rr int l=1,r;l<=n;l=r+1)
			ans+=(phi[r=n/(n/l)]-phi[l-1])*((phi[n/l]<<1)-1);
		print(ans),putchar(10);
	}
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值