P3911最小公倍数之和 题解

这篇博客介绍了如何利用莫比乌斯反演解决数论问题,具体展示了两个实例:一是计算两两不同整数的最大公约数的乘积之和,二是对同一问题的模意义下的计算。博主详细阐述了计算过程,并提供了相应的C++代码实现。通过这两个例子,读者可以深入理解莫比乌斯反演在实际问题中的应用和威力。
摘要由CSDN通过智能技术生成

2021-7-31


这道题使用莫比乌斯反演,比较套路化

P3911

∑ i = 1 n ∑ j = 1 n l c m ( A i , A j ) \sum^{n}_{i=1}\sum^{n}_{j=1}lcm(A_i,A_j) i=1nj=1nlcm(Ai,Aj)

可以发现 A i A_i Ai的值不算特别大,瞬间想到桶(剧透)

我们定义 a i a_i ai为数 i i i的出现次数, m m m为一个值出现最多的次数。

那么开始推式子:

A n s = ∑ i = 1 m ∑ j = 1 m a i a j × l c m ( i , j ) Ans=\sum^{m}_{i=1}\sum^{m}_{j=1}a_ia_j\times lcm(i,j) Ans=i=1mj=1maiaj×lcm(i,j)
根据小学奥数知识(真就小奥)的 a × b = g c d ( a , b ) × l c m ( a , b ) a\times b=gcd(a,b)\times lcm(a,b) a×b=gcd(a,b)×lcm(a,b)

可得:

A n s = ∑ d = 1 m ∑ i = 1 m ∑ j = 1 m i j a i a j d [ g c d ( i , j ) = d ] Ans=\sum_{d=1}^{m}\sum^{m}_{i=1}\sum^{m}_{j=1}\frac{ija_ia_j}{d}[gcd(i,j)=d] Ans=d=1mi=1mj=1mdijaiaj[gcd(i,j)=d]

A n s = ∑ d = 1 m 1 d ∑ i = 1 m ∑ j = 1 m i j a i a j [ g c d ( i , j ) = d ] Ans=\sum_{d=1}^{m}\frac{1}{d}\sum^{m}_{i=1}\sum^{m}_{j=1}ija_ia_j[gcd(i,j)=d] Ans=d=1md1i=1mj=1mijaiaj[gcd(i,j)=d]

f ( x ) = ∑ i = 1 m ∑ j = 1 m i j a i a j [ g c d ( i , j ) = d ] f(x)=\sum^{m}_{i=1}\sum^{m}_{j=1}ija_ia_j[gcd(i,j)=d] f(x)=i=1mj=1mijaiaj[gcd(i,j)=d]

构造 F ( x ) = ∑ x ∣ d f ( d ) F(x)=\sum_{x|d}f(d) F(x)=xdf(d)

可得

F ( x ) = ∑ i = 1 m ∑ j = 1 m i j a i a j [ x ∣ g c d ( i , j ) ] F(x)=\sum^{m}_{i=1}\sum^{m}_{j=1}ija_ia_j[x|gcd(i,j)] F(x)=i=1mj=1mijaiaj[xgcd(i,j)]
= ∑ x ∣ i ∑ x ∣ j i j a i a j =\sum_{x|i}\sum_{x|j}ija_ia_j =xixjijaiaj
= ∑ x ∣ i i a i × ∑ x ∣ j j a j =\sum_{x|i}ia_i\times \sum_{x|j}j a_j =xiiai×xjjaj
= ( ∑ x ∣ i i a i ) 2 =(\sum_{x|i}ia_i)^2 =(xiiai)2

由反演可得:

f ( d ) = ∑ x = 1 ⌊ m d ⌋ μ ( x ) F ( d x ) f(d)=\sum_{x=1}^{\lfloor \frac{m}{d}\rfloor} \mu(x) F(dx) f(d)=x=1dmμ(x)F(dx)

那么带入 A n s Ans Ans

A n s = ∑ d = 1 m 1 d f ( d ) Ans=\sum^{m}_{d=1}\frac{1}{d}f(d) Ans=d=1md1f(d)
= ∑ d = 1 m 1 d ∑ g = 1 ⌊ m d ⌋ μ ( g ) F ( g d ) =\sum^{m}_{d=1}\frac{1}{d}\sum_{g=1}^{\lfloor \frac{m}{d}\rfloor} \mu(g) F(gd) =d=1md1g=1dmμ(g)F(gd)

我们可以用 O ( n log ⁡ n ) O(n \log n) O(nlogn)的时间复杂度求出 F F F,然后用 O ( n log ⁡ n ) O(n \log n) O(nlogn)的时间复杂度求出该式子

代码:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
#define int long long
const int Maxn=50010;
int n,Ar[Maxn];
int m,Tong[Maxn];
int f[Maxn],ans;
int ret,prime[Maxn],mu[Maxn];
bool flag[Maxn];
void get_mu()
{
	mu[1]=1;
	for(int i=2;i<=m;i++)
	{
		if(!flag[i])
		{
			prime[++ret]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=ret && prime[j]<=m/i;j++)
		{
			flag[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0;
				break;
			}else{
				mu[i*prime[j]]=-mu[i];
			}
		}
	}
}
signed main()
{
	
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&Ar[i]);
		m=max(m,Ar[i]);
		Tong[Ar[i]]++;
	}
	//m=50000;
	for(int i=1;i<=m;i++)
	{
		for(int j=i;j<=m;j+=i)
		{
			f[i]+=Tong[j]*j;
		}
	}
	for(int i=1;i<=m;i++)
	{
		f[i]*=f[i];
	}
	get_mu();
	for(int i=1;i<=m;i++)
	{
		int tot=0;
		for(int j=1;j<=m/i;j++)
		{
			tot+=mu[j]*f[i*j];
		}
		ans+=tot/i;
	}
	printf("%lld\n",ans);
	return 0;
}

然而还有一道比较相似的题目:

[AGC038C] LCMs

只不过是把问题改为了:

∑ i = 1 n ∑ j = i + 1 n l c m ( A i , A j ) \sum^{n}_{i=1}\sum^{n}_{j=i+1}lcm(A_i,A_j) i=1nj=i+1nlcm(Ai,Aj)的值模 998244353 998244353 998244353

然而式子也比较像。

双倍经验!!!111

代码:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int Mod=998244353;
const int inv2=499122177;
#define int long long
const int Maxn=1e6+10;
int n,Ar[Maxn];
int m,Tong[Maxn];
int f[Maxn],ans;
int ret,prime[Maxn],mu[Maxn];
bool flag[Maxn];
void get_mu()
{
	mu[1]=1;
	for(int i=2;i<=m;i++)
	{
		if(!flag[i])
		{
			prime[++ret]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=ret && prime[j]<=m/i;j++)
		{
			flag[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0;
				break;
			}else{
				mu[i*prime[j]]=-mu[i];
			}
		}
	}
}
signed main()
{
	
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&Ar[i]);
		m=max(m,Ar[i]);
		Tong[Ar[i]]++;
		ans-=Ar[i];
	}
	//m=50000;
	get_mu();
	for(int i=1;i<=m;i++)
	{
		for(int j=i;j<=m;j+=i)
		{
			f[j]=(f[j]+mu[i]*i%Mod);
		}
	}
	for(int i=1;i<=m;i++)
	{
		int tot=0;
		for(int j=1;j<=m/i;j++)
		{
			tot=(tot+j*Tong[i*j]%Mod)%Mod;
		}
		ans=(ans+i*f[i]%Mod*tot%Mod*tot%Mod)%Mod;
	}
    ans=(ans*inv2%Mod+Mod)%Mod;
	printf("%lld\n",ans);
	return 0;
}

莫比乌斯反演大法好!!!11

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值