「HAOI2011」Problem b 题解
本文网址:https://www.cnblogs.com/zsc985246/p/17396656.html ,转载请注明出处。
前言
莫比乌斯反演:对于两个数论函数 \(f(n),g(n)\),如果 \(f(n)=\sum_{d|n}g(d)\),那么 \(g(n)=\sum_{d|n}f(\frac{n}{d})\mu(d)\)。
证明:
将 \(f(n)=\sum_{d|n}g(d)\) 代入,得到:
\[g(n)=\sum_{d|n}\mu(d)\sum_{x|\frac{n}{d}}g(x)\\ \]\[\ \ \ \ \ \ \ =\sum_{x|n}g(x)\sum_{d|\frac{n}{x}}\mu(d)\\ \]\[\ \ \ \ \ \ =\sum_{x|n}g(x)[\frac{n}{x}=1]\\ \]\[=g(n)\ \ \ \ \ \ \ \ \ \ \ \ \ \]得证。
注意,我们在它的证明中用到了莫比乌斯函数的一个性质:\(\sum_{d|n}\mu(d)=[n=1]\)。
那么,我们可以反过来利用这个性质:\([n=1]=\sum_{d|n}\mu(d)\)。
这便是莫比乌斯反演的本质。
题目大意
给出 \(a,b,c,d,k\),求:
\[\sum_{x=a}^{b}\sum_{y=c}^{d}[\gcd(x,y)=k]
\]
思路
注意到,原式中有四个限制 \(a,b,c,d\)。尝试简化。
容易想到容斥。令 \(F(a,b)=\sum_{x=1}^{a}\sum_{y=1}^{b}[\gcd(x,y)=k]\),那么原式就等于 \(F(c,d)-F(a-1,d)-F(b-1,c)+F(a-1,b-1)\)。
那我们只需要化简 \(F(a,b)\) 就好了。
\[F(a,b)=\sum_{x=1}^{a}\sum_{y=1}^{b}[\gcd(x,y)=k]\\
\]
\[\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\sum_{x=1}^{a}\sum_{y=1}^{b}[\gcd(\frac{x}{k},\frac{y}{k})=1]\\
\]
\[\ \ \ \ \ \ \ \ \ \ \ \ =\sum_{x=1}^{\lfloor\frac{a}{k}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{k}\rfloor}[\gcd(x,y)=1]
\]
这里我们用 \([n=1]=\sum_{d|n}\mu(d)\) 把 \([\gcd(x,y)=1]\) 拆开。
\[=\sum_{x=1}^{\lfloor\frac{a}{k}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{k}\rfloor}\sum_{d|\gcd(x,y)}\mu(d)\\
\]
\[=\sum_{x=1}^{\lfloor\frac{a}{k}\rfloor}\sum_{d|x}\mu(d)\sum_{y=1}^{\lfloor\frac{b}{k}\rfloor}[d|y]\\
\]
\[\ \ \ \ \ \ =\sum_{d=1}^{\lfloor\frac{a}{k}\rfloor}\mu(d)\sum_{x=1}^{\lfloor\frac{a}{k}\rfloor}[d|x]\sum_{y=1}^{\lfloor\frac{b}{k}\rfloor}[d|y]\\
\]
\[=\sum_{d=1}^{\lfloor\frac{a}{k}\rfloor}\mu(d)\sum_{x=1}^{\lfloor\frac{a}{kd}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{kd}\rfloor}1\ \ \ \ \ \\
\]
\[=\sum_{d=1}^{\lfloor\frac{a}{k}\rfloor}\mu(d)\lfloor\frac{a}{kd}\rfloor\lfloor\frac{b}{kd}\rfloor\ \ \\
\]
然后我们发现,可以直接使用整除分块计算答案了。
代码实现
两个数的整除分块不要写错了。
#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
const ll N=1e6+10;
using namespace std;
ll mu[N],tot,p[N],vis[N];
void init(ll n){//筛莫比乌斯函数
mu[1]=1;
For(i,2,n){
if(!vis[i])p[++tot]=i,mu[i]=-1;
For(j,1,tot){
if(i*p[j]>n)break;
vis[i*p[j]]=1;
if(i%p[j]==0)break;
mu[i*p[j]]=-mu[i];
}
}
For(i,1,n)mu[i]+=mu[i-1];//前缀和
}
ll calc(ll a,ll b){
ll ans=0,k;
for(ll i=1;i<=min(a,b);i=k+1){//两个数的整除分块,不要写挂了
k=min(a/(a/i),b/(b/i));
ans+=(a/i)*(b/i)*(mu[k]-mu[i-1]);//按公式计算
}
return ans;
}
void mian(){
ll a,b,c,d,k;
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
a=(a-1)/k,b=b/k,c=(c-1)/k,d=d/k;//提前除以k
printf("%lld\n",calc(b,d)-calc(b,c)-calc(a,d)+calc(a,c));//前缀和
}
int main(){
init(1e6);
int T=1;
scanf("%d",&T);
while(T--)mian();
return 0;
}
尾声
如果你发现了问题,你可以直接回复这篇题解
如果你有更好的想法,也可以直接回复!

浙公网安备 33010602011771号