【XSY2719】prime(积性函数,莫比乌斯反演)

题意:求 \(\left(\sum\limits_{i=1}^n2^{f(i)}\right)\bmod 998244353\),其中 \(f(i)\) 表示 \(i\) 的不同质因子的个数,\(n\leq 10^{12}\)


一开始发现 \(g(x)=2^{f(x)}\) 是积性函数以为能直接 min_25 筛(

结果时间爆炸(

考虑 \(2^{f(i)}\) 的组合意义,得到 \(2^{f(i)}=\sum\limits_{j|i}\mu^2(j)\)

于是:

\[\begin{aligned} &\sum_{i=1}^n2^{f(i)}\\ =&\sum_{i=1}^n\sum_{j|i}\mu^2(j)\\ =&\sum_{i=1}^n\lfloor\dfrac{n}{i}\rfloor\mu^2(i) \end{aligned} \]

如果我们能快速求出 \(\mu^2(i)\)\(n\) 的基本和组上的前缀和,就能整除分块了。

注意到设 \(d\)\(x\) 的最大平方因子(如 \(x=3\)\(d=1\)\(x=24\)\(d=2\)),那么:

\[\mu^2(x)=[d=1]=\sum_{i|d}\mu(i) \]

根据 \(d\) 的定义,\(x\) 可以写成 \(y\times d^2\) 的形式,其中 \(y\) 没有平方因子。

那么枚举 \(i|d\) 相当于枚举 \(i^2|x\),于是 \(\mu^2(x)=\sum\limits_{i^2|x}\mu(i)\)

于是原式为:

\[\begin{aligned} =&\sum_{i=1}^n\lfloor\dfrac{n}{i}\rfloor \sum_{d^2|i}\mu(d)\\ =&\sum_{d=1}^{\sqrt n}\mu(d)\sum_{j=1}^{n/(d^2)}\lfloor\dfrac{n}{d^2j}\rfloor \end{aligned} \]

\(g(n)=\sum\limits_{i=1}^n\lfloor\dfrac{n}{i}\rfloor\),于是原式为:

\[=\sum_{d=1}^{\sqrt n}\mu(d)g\left(\lfloor\dfrac{n}{d^2}\rfloor\right) \]

我们暴力枚举每一个 \(d\),并每次暴力整除分块求出 \(g\) 即可。

时间复杂度:

\[\sum _{i=1}^{\sqrt n}O\left(\sqrt{\dfrac{n}{i^2}}\right)=\sum_{i=1}^{\sqrt n}O\left(\dfrac{\sqrt n}{i}\right)=O\left(\sqrt n\ln \sqrt n\right) \]

代码如下:

#include<bits/stdc++.h>

#define N 1000010
#define ll long long

using namespace std;

namespace modular
{
	const int mod=998244353;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

ll n;
int sn;
int cnt,prime[N],mu[N];
bool notprime[N];

void init()
{
	mu[1]=1;
	for(int i=2;i<=sn;i++)
	{
		if(!notprime[i])
		{
			prime[++cnt]=i;
			mu[i]=mod-1;
		}
		for(int j=1,x;j<=cnt&&(x=i*prime[j])<=sn;j++)
		{
			notprime[x]=1;
			if(!(i%prime[j])) break;
			mu[x]=mul(mu[i],mu[prime[j]]);
		}
	}
}

int g(ll n)
{
	int ans=0;
	for(ll l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans=add(ans,mul((r-l+1)%mod,(n/l)%mod));
	}
	return ans;
}

int main()
{
	scanf("%lld",&n);
	sn=sqrt(n);
	init();
	int ans=0;
	for(int d=1;d<=sn;d++)
		ans=add(ans,mul(mu[d],g(n/d/d)));
	printf("%d\n",ans);
	return 0;
}
posted @ 2022-10-30 10:40  ez_lcw  阅读(47)  评论(0编辑  收藏  举报