P3327 [SDOI2015]约数个数和
题意:
设d(x)为x的约数个数,给定 n , m n,m n,m,求
∑ i = 1 n ∑ j = 1 m d ( i j ) \sum_{i=1}^{n}\sum_{j=1}^{m}d(ij) i=1∑nj=1∑md(ij)
Solution:
首先需知道一个推导结果:
d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1] d(ij)=x∣i∑y∣j∑[gcd(x,y)=1]
然后开始式子的推导:
∑ i = 1 n ∑ j = 1 m d ( i j ) = ∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] = ∑ x = 1 n ∑ y = 1 m ⌊ n x ⌋ ⌊ x m ⌋ [ g c d ( x , y ) = 1 ] = ∑ x = 1 n ∑ y = 1 m ⌊ n x ⌋ ⌊ x m ⌋ ∑ d ∣ g c d ( x . y ) μ ( d ) = ∑ d = 1 m i n ( n , m ) μ ( d ) ∑ x = 1 ⌊ n d ⌋ ⌊ n d x ⌋ ∑ y = 1 ⌊ m d ⌋ ⌊ m d y ⌋ \sum_{i=1}^{n}\sum_{j=1}^{m}d(ij) \\ =\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{x|i}\sum_{y|j}[gcd(x,y)=1] \\ =\sum_{x=1}^{n}\sum_{y=1}^{m}\lfloor\frac{n}{x}\rfloor\lfloor\frac{x}{m}\rfloor[gcd(x,y)=1] \\ =\sum_{x=1}^{n}\sum_{y=1}^{m}\lfloor\frac{n}{x}\rfloor\lfloor\frac{x}{m}\rfloor\sum_{d|gcd(x.y)}\mu(d) \\ =\sum_{d=1}^{min(n,m)}\mu(d)\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{n}{dx}\rfloor\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{m}{dy}\rfloor i=1∑nj=1∑md(ij)=i=1∑nj=1∑mx∣i∑y∣j∑[gcd(x,y)=1]=x=1∑ny=1∑m⌊xn⌋⌊mx⌋[gcd(x,y)=1]=x=1∑ny=1∑m⌊xn⌋⌊mx⌋d∣gcd(x.y)∑μ(d)=d=1∑min(n,m)μ(d)x=1∑⌊dn⌋⌊dxn⌋y=1∑⌊dm⌋⌊dym⌋
到这里就可以看出用整除分块来求解。
代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>P;
typedef long long ll;
const int N=5e4;
int mu[N+5],prime[N+5],notPrime[N+5],cnt=0,sumMu[N+5];
ll sum[N+5];
void initMu()
{
mu[1]=1;
for(int i=2;i<=N;i++)
{
if(!notPrime[i])
{
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&1ll*i*prime[j]<=N;j++)
{
notPrime[i*prime[j]]=1;
if(i%prime[j])mu[i*prime[j]]=-mu[i];
else break;
}
}
for(int i=1;i<=N;i++)
{
sumMu[i]=sumMu[i-1]+mu[i];
for(int l=1,r;l<=i;l=r+1)
{
r=i/(i/l);
sum[i]+=1ll*i/l*(r-l+1);
}
}
}
int n,m,t;
int main()
{
initMu();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
ll res=0;
int M=min(n,m);
for(int l=1,r;l<=M;l=r+1)
{
r=min(n/(n/l),m/(m/l));
res+=1ll*(sumMu[r]-sumMu[l-1])*sum[n/l]*sum[m/l];
}
printf("%lld\n",res);
}
return 0;
}