# [bzoj3994] [SDOI2015] 约数个数和

### Description

$d(x)$$x$ 的约数个数，给定 $N$$M$，求 $\sum\limits_{i=1}^N \sum\limits_{j=1}^M d(ij)$

### Output

$T$ 行，每行一个整数，表示你所求的答案。

2

7 4

5 6

110

121

### HINT

$1<=N, M<=50000$
$1<=T<=50000$

## 想法

$d(i,j)=\sum\limits_{x|i} \sum\limits_{y|j} [gcd(x,y)==1]$

\begin{equation*} \begin{aligned} &\sum\limits_{i=1}^n \sum\limits_{j=1}^m d(ij) \\ =&\sum\limits_{i=1}^n \sum\limits_{j=1}^m \sum\limits_{x|i} \sum\limits_{y|j} [gcd(x,y)==1] \\ =&\sum\limits_{i=1}^n \sum\limits_{j=1}^m [gcd(x,y)==1] \times \lfloor \frac{n}{x} \rfloor \times \lfloor \frac{m}{y} \rfloor \\ \end{aligned} \end{equation*}

$f(i)=\sum\limits_{i=1}^n \sum\limits_{j=1}^m [gcd(x,y)==1] \times \lfloor \frac{n}{x} \rfloor \times \lfloor \frac{m}{y} \rfloor$

\begin{equation*} \begin{aligned} F(i)&=f(i)+f(2i)+... \\ &=\sum\limits_{x=1}^{\lfloor \frac{n}{i} \rfloor} \sum\limits_{y=1}^{\lfloor \frac{m}{i} \rfloor} \lfloor \frac{n}{ix} \rfloor \lfloor \frac{m}{iy} \rfloor \\ &=\sum\limits_{x=1}^{\lfloor \frac{n}{i} \rfloor} \lfloor \frac{n}{ix} \rfloor \sum\limits_{y=1}^{\lfloor \frac{m}{i} \rfloor} \lfloor \frac{m}{iy} \rfloor \end{aligned} \end{equation*}

$f(i)=\sum\limits_{i|d} \mu(\frac{d}{i}) s(\frac{n}{d}) s(\frac{m}{d})$

\begin{equation*} \begin{aligned} ans&=f(1) \\ &=\sum\limits_{i=1}^{min(n,m)} \mu(i) s(\frac{n}{i})s(\frac{m}{i}) \end{aligned} \end{equation*}

## 代码

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 50005;
typedef long long ll;

ll s[N];
int mu[N],p[N],prime[N],pnum,sum[N];
void getp(){
mu[1]=sum[1]=1;
for(int i=2;i<N;i++) p[i]=1;
for(int i=2;i<N;i++){
if(p[i]) prime[pnum++]=i,mu[i]=-1;
for(int j=0;j<pnum && (ll)prime[j]*i<N;j++){
p[i*prime[j]]=0;
if(i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
sum[i]=sum[i-1]+mu[i];
}
}
void gets(){
for(int x=1;x<N;x++){
for(int l=1,r;l<=x;l=r+1){
r=x/(x/l);
s[x]+=1ll*(x/l)*(r-l+1);
}
}
}

int main()
{
int T,n,m;
getp(); gets();

scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
ll ans=0;
for(int l=1,r;l<=n && l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=s[n/l]*s[m/l]*(sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
}

return 0;
}
﻿


posted @ 2019-03-15 22:49  秋千旁的蜂蝶~  阅读(81)  评论(0编辑  收藏  举报