# 【BZOJ】3994: [SDOI2015]约数个数和

## 题意：

$T(1 \le T \le 50000)$次询问，每次给出$n, m(1 \le n, m \le 50000)$，求$\sum_{i=1}^{n} \sum_{j=1}^{m} d(ij)$，其中$d(n)$表示$n$的约数个数

## 分析

$$\sum_{x_1}^{y_1} \sum_{x_2}^{y_2} \cdots \sum_{x_k}^{y_k} d(x_1 x_2 \cdots x_k) = \sum_{x_1}^{y_1} \sum_{x_2}^{y_2} \cdots \sum_{x_k}^{y_k} \prod_{i=1}^{k} \left \lfloor \frac{y_i}{x_i} \right \rfloor \prod_{i < j } [(x_i, x_j)=1]$$

（证明是二大重数学归纳，数学恐惧症的快快离开。

$d_{k+1}(y_1, y_2, \cdots, y_k) = d(y_1 y_2 \cdots y_k) = f_{k+1}(y_1, y_2, \cdots, y_k) = \sum_{x_1|y_1} \sum_{x_2|y_2} \cdots \sum_{x_k|y_k} \prod_{i < j} [(x_i, x_j)=1]$

## 题解

 \begin{align} ans & = \sum_{i=1}^{n} \sum_{j=1}^{m} d(ij) \\

& =
\sum_{i=1}^{n}
\sum_{j=1}^{m} \left \lfloor \frac{n}{i} \right \rfloor \left \lfloor \frac{m}{j} \right \rfloor [(i, j)=1]
\

& =
\sum_{d=1}^{n} \mu(d)
\sum_{i=1}^{ \left \lfloor \frac{n}{d} \right \rfloor }
\sum_{j=1}^{ \left \lfloor \frac{m}{d} \right \rfloor } \left \lfloor \frac{n}{id} \right \rfloor \left \lfloor \frac{m}{jd} \right \rfloor
\

& =
\sum_{d=1}^{n} \mu(d)
\sum_{i=1}^{ \left \lfloor \frac{n}{d} \right \rfloor } \left \lfloor \frac{ \left \lfloor \frac{n}{d} \right \rfloor }{i} \right \rfloor
\sum_{j=1}^{ \left \lfloor \frac{m}{d} \right \rfloor } \left \lfloor \frac{ \left \lfloor \frac{m}{d} \right \rfloor }{j} \right \rfloor
\
\end{align}

$</p> 我们用O(n^{1.5})预处理d(n) = \sum_{i=1}^{n} \left \lfloor \frac{n}{i} \right \rfloor，然后就解决拉（其实是可以乱搞一下然后用线性筛筛的） #include <bits/stdc++.h> using namespace std; typedef long long ll; const int Lim=50000, N=50005; int p[N], np[N], pcnt, mu[N]; ll d[N]; void init() { mu[1]=1; for(int i=2; i<=Lim; ++i) { if(!np[i]) { p[pcnt++]=i; mu[i]=-1; } for(int j=0; j<pcnt; ++j) { int t=p[j]*i; if(t>Lim) break; np[t]=1; if(i%p[j]==0) break; mu[t]=-mu[i]; } } for(int n=1; n<=Lim; ++n) { for(int i=1, pos=1; i<=n; i=pos+1) { pos=n/(n/i); d[n]+=(ll)(pos-i+1)*(n/i); } mu[n]+=mu[n-1]; } } void work() { int n, m; ll ans=0; scanf("%d%d", &n, &m); if(n>m) { swap(n, m); } for(int i=1, pos=1; i<=n; i=pos+1) { pos=min(n/(n/i), m/(m/i)); ans+=(ll)(mu[pos]-mu[i-1])*d[n/i]*d[m/i]; } printf("%lld\n", ans); } int main() { int T; scanf("%d", &T); init(); while(T--) { work(); } return 0; }$

posted @ 2015-11-22 17:56  iwtwiioi  阅读(1089)  评论(0编辑  收藏  举报