CCPC-Wannafly Winter Camp Day3 F.小清新数论(数论分块+(莫比乌斯反演/杜教筛))

题目

\sum_{i=1}^{n}\sum_{j=1}^{n}\mu (gcd(i,j))

Div2:n<=1e7

Div1:n<=1e10

思路来源

Div2:https://blog.csdn.net/Eternally831143/article/details/86755286(反演)

Div1:https://blog.csdn.net/Anoy_acer/article/details/86654825(杜教筛)

题解1(莫比乌斯反演 约数变倍数)

ans=\sum_{i=1}^{n}\sum_{j=1}^{n}\mu (gcd(i,j))

枚举d,ans=\sum_{d=1}^{n}\mu (d)\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd(i,j)==d]

g(d)=\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd(i,j)==d]ans=\sum_{d=1}^{n}\mu (d)*g(d)

f(d)=d|gcd(i,j),则gcd(i,j)可取d,2d,...,[\frac{n}{d}]*d,有f(d)=\sum_{​{i=1}}^{[\frac{n}{d}]}g(i*d)

同乘μ反演一下,有g(d)=\sum_{​{i=1}}^{[\frac{n}{d}]}f(i*d)*\mu(i)

另一方面,gcd(i,j)是d的倍数,只需i是d的倍数,j是d的倍数,这样的数只有d,2d,...,[\frac{n}{d}]*d

f(d)=[\frac{n}{d}][\frac{n}{d}],有f(i*d)=[\frac{n}{i*d}]^{2}g(d)=\sum_{​{i=1}}^{[\frac{n}{d}]}[\frac{n}{i*d}]^{2}*\mu(i)

ans=\sum_{d=1}^{n}\mu (d)*g(d)

先数论分块求g(d),对于所有[\frac{n}{i}]相同的部分[\frac{n}{i*d}]^{2}相同,[l,r]区间求和\mu(i)

然后数论分块求ans,对于所有[\frac{n}{d}]相同的部分,

k=[\frac{n}{d}],这段区间中每个g(d)=\sum_{​{i=1}}^{k}[\frac{k}{i}]^{2}*\mu(i),显然相同,[l,r]区间求和\mu(i),求得ans

 

后记:发现还是直接用e=mu*1(*为卷积)硬拆方便,

无脑拆[gcd(i,j)==1]=\sum_{k|gcd(i,j)}\mu (k),枚举k,找k的倍数

题解2(杜教筛 构造欧拉函数前缀和)

最后的答案ans=\sum_{i=1}^{n}\mu (i)*(P(\frac{n}{i})*2-1)

F(\frac{n}{i})=(P(\frac{n}{i})*2-1),是因为P只计入gcd(i,j)中i>=j部分,乘2一并计入j>=i部分,-1减去i==j部分

先欧拉筛预处理前1e7项,作前缀和,做杜教筛的查表部分

对ans分块,求出所有n/i贡献相同的[l,r]部分,其贡献为F(n/i)*(mu[r]-mu[l-1]),求和即可

djsmu和djsphi由于常用,就当做板子吧,推导可以用构造推导

心得

主要要会推导式子,数论分块要熟练

入门了之后,反演和杜教筛就是刷题找感觉了吧

代码1(n<=1e7)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=1e7+10;
bool ok[maxn];
int prime[maxn],mu[maxn],cnt;
ll n,ans;
void sieve()
{
	mu[1]=1;
	for(ll i=2;i<maxn;++i)
	{
		if(!ok[i])
		{
			prime[cnt++]=i;
			mu[i]=-1;
		}
		for(int j=0;j<cnt;++j)
		{
			if(i*prime[j]>=maxn)break;
			ok[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0;//如果开的是全局,就不用管 
				break; 
			}
			else mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=2;i<maxn;++i)
	mu[i]=mu[i-1]+mu[i];//mu前缀和 
}
ll g(ll d)
{
	ll ans=0;
	for(int l=1,r;l<=n/d;l=r+1)
	{
		r=n/(n/l);
		ans=ans+1ll*(mu[r]-mu[l-1]+mod)*(n/d/l)%mod*(n/d/l)%mod;
		if(ans>=mod)ans-=mod;
		if(ans<0)ans+=mod;
	}
	return ans;
}
int main()
{
	sieve();
	scanf("%lld",&n);
	for(int l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans+=1ll*(mu[r]-mu[l-1]+mod)%mod*g(l)%mod;
		if(ans>=mod)ans-=mod;
		if(ans<0)ans+=mod;
	}
	printf("%lld\n",ans);
	return 0;
}

代码2(n<=1e10)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map> 
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=1e7+10;
bool ok[maxn];
int prime[maxn],mu[maxn],cnt;
ll phi[maxn];
map<ll,int>smu;//mu的前缀和 
map<ll,ll>sphi;//phi的前缀和 
void sieve()
{
	phi[1]=mu[1]=1;
	for(ll i=2;i<maxn;++i)
	{
		if(!ok[i])
		{
			prime[cnt++]=i;
			phi[i]=i-1;
			mu[i]=-1;
		}
		for(int j=0;j<cnt;++j)
		{
			ll k=i*prime[j];
			if(k>=maxn)break;
			ok[k]=1;
			if(i%prime[j]==0)
			{
				phi[k]=phi[i]*prime[j];
				mu[k]=0;
				break; 
			}
			else
			{
			 phi[k]=phi[i]*(prime[j]-1);
			 mu[k]=-mu[i];
		    }
		}
	}
	for(int i=1;i<maxn;++i)//搞前缀和 
	{
		mu[i]=mu[i-1]+mu[i];
		phi[i]=phi[i-1]+phi[i];
	}
}
int djsmu(ll x)//求mu前缀和
{
    if(x<maxn)return mu[x];
    if(smu[x])return smu[x];
    int ans=1;
    for(ll l=2,r;l<=x;l=r+1)
    {
        r=x/(x/l);
        ans-=1ll*(r-l+1)*djsmu(x/l);
    }
    return smu[x]=ans;
}
ll djsphi(ll x)	//求phi 前缀和
{
    if(x<maxn)return phi[x]%mod;
    if(sphi[x])return sphi[x];
    ll ans;//x*(x+1)/2
	if(x%2==0)ans=(x/2%mod)*((x+1)%mod)%mod;
	else ans=((x+1)/2)%mod*(x%mod)%mod;
    for(ll l=2,r;l<=x;l=r+1)
    {
        r=x/(x/l);
        ans=(ans-(r-l+1)%mod*djsphi(x/l)%mod);
        if(ans>=mod)ans-=mod;
        if(ans<0)ans+=mod;
    }
    return sphi[x]=ans;
}
ll n,ans;
int main()
{
	sieve();
	scanf("%lld",&n);
	for(ll l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans+=(djsmu(r)-djsmu(l-1)+mod)%mod*(djsphi(n/l)*2-1+mod)%mod;
		if(ans>=mod)ans-=mod;
		if(ans<0)ans+=mod;
	}
	printf("%lld\n",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值