Label
利用Möbius函数改写容斥式经典题
Description
给定QQQ组询问,每组询问给定三个正整数a,b,d(Q,a,b,d≤5×104)a,b,d(Q,a,b,d\leq5\times 10^4)a,b,d(Q,a,b,d≤5×104),求
∑i=1a∑j=1b[gcd(i,j)==d]\sum_{i=1}^{a}\sum_{j=1}^{b}[gcd(i,j)==d]i=1∑aj=1∑b[gcd(i,j)==d]
Solution
这个题显然可以用反演做,推出来的式子和利用容斥推得的式子基本一样。此处只讲容斥做法。
在luoguP1447里,我们曾利用fn=⌊ad⌋⌊bd⌋−∑i=2id≤min(a,b)fidf_n=\lfloor \frac{a}{d} \rfloor\lfloor \frac{b}{d} \rfloor-\sum_{i=2}^{id\leq min(a,b)}f_{id}fn=⌊da⌋⌊db⌋−∑i=2id≤min(a,b)fid来O(nlogn)O(nlogn)O(nlogn)求f1∼fnf_1\sim f_nf1∼fn(fk=∑i=1a∑j=1b[gcd(i,j)==k])(f_k=\sum_{i=1}^{a}\sum_{j=1}^{b}[gcd(i,j)==k])(fk=∑i=1a∑j=1b[gcd(i,j)==k]),但对于此题,由于a,ba,ba,b是变化的,故若想以与P1447相同的容斥思路来解此题,那么对于每一次询问,我们都需要重新求一遍f1∼fnf_1\sim f_nf1∼fn,这样一来算法总复杂度O(n2logn)O(n^2logn)O(n2logn),不可取,故考虑更优的容斥方法。
之前的容斥方法是将最大公约数为kdkdkd的数的集合从被ddd整除的数的集合中剔除掉从而得到fdf_dfd,故此处我们考虑将原条件变形以尝试得到新的限制(约束)条件。
由于常规套路:gcd(i,j)=d↔gcd(id,jd)=1gcd(i,j)=d\leftrightarrow gcd(\frac{i}{d},\frac{j}{d})=1gcd(i,j)=d↔gcd(di,dj)=1,故首先:
∑i=1a∑j=1b[gcd(i,j)==d]↔∑i=1⌊ad⌋∑j=1⌊bd⌋[gcd(i,j)==1]\sum_{i=1}^{a}\sum_{j=1}^{b}[gcd(i,j)==d]\leftrightarrow \sum_{i=1}^{\lfloor \frac{a}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{b}{d} \rfloor}[gcd(i,j)==1]i=1∑aj=1∑b[gcd(i,j)==d]↔i=1∑⌊da⌋j=1∑⌊db⌋[gcd(i,j)==1]
根据经典的容斥思路∣⋂i=1nSi∣=∣U∣−∣⋃i=1n∁USi∣|\bigcap_{i=1}^{n}S_i|=|U|-|\bigcup_{i=1}^{n}\complement_US_{i}|∣i=1⋂nSi∣=∣U∣−∣i=1⋃n∁USi∣,考虑满足互质的有序二元组所满足的限制,其即为:∀(x,y)∀p∈prime,p∤x∧p∤y\forall(x,y)\forall p\in prime,p\nmid x\wedge p\nmid y∀(x,y)∀p∈prime,p∤x∧p∤y。
那么,令∁USi={x∣pi∣x}\complement_US_{i}=\{x|p_i|x\}∁USi={x∣pi∣x},且多个∁USi\complement_US_{i}∁USi的交={x∣∏pi∣x}\{x|\prod p_i|x\}{x∣∏pi∣x};又由于根据Möbius函数的定义,含有奇数个质因子时值为-1,偶数个质因子时值为111,而根据此处容斥式的定义,∏pi\prod p_i∏pi内含有pip_ipi的个数奇偶性正好对应了容斥式内的正负;而且根据SiS_iSi定义,含有多个相同奇因子的iii对应集合不予考虑,所以,我们可以利用这一点写出此题的容斥式:
设D(d)=∑i=1⌊ad⌋∑j=1⌊bd⌋[p∣i∧p∣j]D(d)=\sum_{i=1}^{\lfloor \frac{a}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{b}{d} \rfloor}[p\mid i\wedge p\mid j]D(d)=∑i=1⌊da⌋∑j=1⌊db⌋[p∣i∧p∣j],故:
∑i=1⌊ad⌋∑j=1⌊bd⌋[gcd(i,j)==1]=∑i=1min(⌊ad⌋,⌊bd⌋)μ(i)D(i)==∑i=1min(⌊ad⌋,⌊bd⌋)μ(i)⌊adi⌋⌊bdi⌋\sum_{i=1}^{\lfloor \frac{a}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{b}{d} \rfloor}[gcd(i,j)==1]=\sum_{i=1}^{min(\lfloor \frac{a}{d} \rfloor,\lfloor \frac{b}{d} \rfloor)}\mu(i)D(i)==\sum_{i=1}^{min(\lfloor \frac{a}{d} \rfloor,\lfloor \frac{b}{d} \rfloor)}\mu(i)\lfloor \frac{a}{di} \rfloor\lfloor \frac{b}{di} \rfloor∑i=1⌊da⌋∑j=1⌊db⌋[gcd(i,j)==1]=∑i=1min(⌊da⌋,⌊db⌋)μ(i)D(i)==∑i=1min(⌊da⌋,⌊db⌋)μ(i)⌊dia⌋⌊dib⌋
所以
ans=∑i=1min(⌊ad⌋,⌊bd⌋)μ(i)⌊adi⌋⌊bdi⌋ans=\sum_{i=1}^{min(\lfloor \frac{a}{d} \rfloor,\lfloor \frac{b}{d} \rfloor)}\mu(i)\lfloor \frac{a}{di} \rfloor\lfloor \frac{b}{di} \rfloorans=i=1∑min(⌊da⌋,⌊db⌋)μ(i)⌊dia⌋⌊dib⌋
根据前面所讲的数论分块,上面这个式子可分块求,注意预处理μ(i)\mu(i)μ(i)前缀和。
算法时间复杂度:O(nn)O(n\sqrt n)O(nn)
Code
#include<cstdio>
#include<iostream>
#define ri register int
#define ll long long
using namespace std;
const int MAXN=5e4;
int Q,cnt;
ll a,b,d,miu[MAXN+20],prime[MAXN+20],sum[MAXN+20],ans;
bool notprime[MAXN+20];
void Mobius()//利用线性筛O(n)求Mobius函数
{
miu[1]=1,notprime[1]=true;
for(ri i=2;i<=MAXN;++i)
{
if(!notprime[i]) prime[++cnt]=i,miu[i]=-1;
for(ri j=1;j<=cnt&&i*prime[j]<=MAXN;++j)
{
notprime[i*prime[j]]=true;
if(i%prime[j]==0) break;
else miu[i*prime[j]]=-miu[i];
}
}
for(ri i=1;i<=MAXN;++i) sum[i]=sum[i-1]+miu[i];
}
int main()
{
std::ios::sync_with_stdio(false);
Mobius();
cin>>Q;
for(ri op=1;op<=Q;++op)
{
cin>>a>>b>>d;
a/=d,b/=d;
ans=0LL;
ll l=1,r,sj=min(a,b);
while(l<=sj)
{
r=min(a/(a/l),b/(b/l));
ans+=(sum[r]-sum[l-1])*(a/l)*(b/l);
l=r+1;
}
cout<<ans<<'\n';
}
return 0;
}