题目:BZOJ3994.
题目大意:设 d ( n ) = ∑ d ∣ n 1 d(n)=\sum_{d|n}1 d(n)=∑d∣n1,给定 T T T组询问 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=1n∑j=1md(ij).
1 ≤ n , m , T ≤ 5 ∗ 1 0 4 1\leq n,m,T\leq 5*10^4 1≤n,m,T≤5∗104.
我们先考虑,如何在知道 i i i和 j j j的情况下如何用 O ( i j ) O(ij) O(ij)的时间复杂度求 d ( i j ) d(ij) d(ij).
考虑知道 i j ij ij后,由于 d d d其实就是约数个数函数,而我们知道,对于任意一个 n = ∏ i = 1 k p i c i n=\prod_{i=1}^{k}p_i^{c_i} n=∏i=1kpici,那么 d ( n ) = ∏ i = 1 k ( c i + 1 ) d(n)=\prod_{i=1}^{k}(c_i+1) d(n)=∏i=1k(ci+1).
对于两个数 n n n和 m m m,考虑如何计算 d ( n m ) d(nm) d(nm).首先我们把两个数分别写成 n = ∏ i = 1 k p i c i , m = ∏ i = 1 k p i q i n=\prod_{i=1}^{k}p_i^{c_i},m=\prod_{i=1}^{k}p_i^{q_i} n=∏i=1kpici,m=∏i=1kpiqi,那么:
d ( n m ) = d ( ∏ i = 1 k p i c i + q i ) = ∏ i = 1 k ( c i + q i + 1 ) d(nm)=d(\prod_{i=1}^{k}p_i^{c_i+q_i})=\prod_{i=1}^{k}(c_i+q_i+1) d(nm)=d(i=1∏kpici+qi)=i=1∏k(ci+qi+1)
对于每一个 ( c i + q i + 1 ) (c_i+q_i+1) (ci+qi+1),我们构造一个 ( 0 , 0 ) (0,0) (0,0)到 ( c i , q i ) (c_i,q_i) (ci,qi)的矩阵,那么我们会发现 ( c i + q i + 1 ) (c_i+q_i+1) (ci+qi+1)等于矩阵中的一个"L"形的区域,即所有坐标中含有 0 0 0的总数.我们发现罪域一个坐标 ( x , y ) (x,y) (x,y)满足 x = 0 x=0 x=0或 y = 0 y=0 y=0时, g c d ( p i x , p i y ) = 1 gcd(p_i^x,p_i^y)=1 gcd(pix,piy)=1,所以可以得到:
d ( n m ) = ∏ i = 1 k ∑ j = 0 c i ∑ t = 0 q i [ g c d ( p i j , p i t ) = 1 ] = ∑ i ∣ n ∑ j ∣ m [ g c d ( i , j ) = 1 ] d(nm)=\prod_{i=1}^{k}\sum_{j=0}^{c_i}\sum_{t=0}^{q_i}[gcd(p_i^j,p_i^t)=1]=\sum_{i|n}\sum_{j|m}[gcd(i,j)=1] d(nm)=i=1∏kj=0∑cit=0∑qi[gcd(pij,pit)=1]=i∣n∑j∣m∑[gcd(i,j)=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 ⌋ ⌊ m y ⌋ ∑ t ∣ x ∧ t ∣ y μ ( t ) = ∑ t = 1 m i n ( n , m ) μ ( t ) ∑ x = 1 ⌊ n t ⌋ ⌊ n t x ⌋ ∑ y = 1 ⌊ m t ⌋ ⌊ m t 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}\left\lfloor\frac{n}{x}\right\rfloor\left\lfloor\frac{m}{y}\right\rfloor\sum_{t|x\wedge t|y}\mu(t)\\ =\sum_{t=1}^{min(n,m)}\mu(t)\sum_{x=1}^{\left\lfloor\frac{n}{t}\right\rfloor}\left\lfloor\frac{n}{tx}\right\rfloor\sum_{y=1}^{\left\lfloor\frac{m}{t}\right\rfloor}\left\lfloor\frac{m}{ty}\right\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⌋⌊ym⌋t∣x∧t∣y∑μ(t)=t=1∑min(n,m)μ(t)x=1∑⌊tn⌋⌊txn⌋y=1∑⌊tm⌋⌊tym⌋
我们设 g ( n ) = ∑ i = 1 n ⌊ n i ⌋ g(n)=\sum_{i=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor g(n)=∑i=1n⌊in⌋,然后可以得到:
= ∑ t = 1 m i n ( n , m ) μ ( t ) ∑ x = 1 ⌊ n t ⌋ ⌊ n t x ⌋ ∑ y = 1 ⌊ m t ⌋ ⌊ m t y ⌋ = ∑ t = 1 m i n ( n , m ) μ ( t ) g ( ⌊ n t ⌋ ) g ( ⌊ m t ⌋ ) =\sum_{t=1}^{min(n,m)}\mu(t)\sum_{x=1}^{\left\lfloor\frac{n}{t}\right\rfloor}\left\lfloor\frac{n}{tx}\right\rfloor\sum_{y=1}^{\left\lfloor\frac{m}{t}\right\rfloor}\left\lfloor\frac{m}{ty}\right\rfloor\\ =\sum_{t=1}^{min(n,m)}\mu(t)g(\left\lfloor\frac{n}{t}\right\rfloor)g(\left\lfloor\frac{m}{t}\right\rfloor) =t=1∑min(n,m)μ(t)x=1∑⌊tn⌋⌊txn⌋y=1∑⌊tm⌋⌊tym⌋=t=1∑min(n,m)μ(t)g(⌊tn⌋)g(⌊tm⌋)
然后我们看看 g g g函数的本质是什么.复读机!
g ( n ) = ∑ i = 1 n ⌊ n i ⌋ = ∑ i = 1 n ∑ i ∣ j ∧ j ∈ [ 1 , n ] 1 = ∑ j = 1 n ∑ i ∣ j 1 = ∑ j = 1 n d ( j ) g(n)=\sum_{i=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor\\ =\sum_{i=1}^{n}\sum_{i|j\wedge j\in[1,n]}1\\ =\sum_{j=1}^{n}\sum_{i|j}1\\ =\sum_{j=1}^{n}d(j) g(n)=i=1∑n⌊in⌋=i=1∑ni∣j∧j∈[1,n]∑1=j=1∑ni∣j∑1=j=1∑nd(j)
发现 g g g函数其实就是 d d d函数的前缀和,而我们知道约数个数函数是可以直接线性筛的.所以预处理出 g g g函数,然后除法分块一下即可,时间复杂度 O ( n + T n ) O(n+T\sqrt{n}) O(n+Tn).
代码如下:
#include
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=50000;
int pr[N+9],tp,b[N+9];
LL d[N+9],num[N+9],mu[N+9];
void sieve(int n){
for (int i=2;i<=n;++i) b[i]=1;
d[1]=mu[1]=num[1]=1;int v;
for (int i=2;i<=n;++i){
if (b[i]) pr[++tp]=i,d[i]=2,num[i]=1,mu[i]=-1;
for (int j=1;j<=tp&&i*pr[j]<=n;++j){
b[v=i*pr[j]]=0;
if (i%pr[j]==0){
num[v]=num[i]+1;d[v]=d[i]/num[v]*(num[v]+1);
mu[v]=0;
break;
}
num[v]=1;d[v]=d[i]<<1;
mu[v]=-mu[i];
}
}
}
LL get(int n,int m){
LL ans=0;
if (n>m) swap(n,m);
for (int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=d[n/l]*d[m/l]*(mu[r]-mu[l-1]);
}
return ans;
}
int n,m;
Abigail start(){
sieve(N);
for (int i=1;i<=N;++i)
d[i]+=d[i-1],mu[i]+=mu[i-1];
}
Abigail into(){
scanf("%d%d",&n,&m);
}
Abigail outo(){
printf("%lld\n",get(n,m));
}
int main(){
start();
int T;
scanf("%d",&T);
while (T--){
into();
outo();
}
return 0;
}