【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]$$

(证明是二大重数学归纳,数学恐惧症的快快离开。
首先对于\(k=1\),我们可以通过算贡献证明。现在我们对\(k>1\)进行归纳:
我们需要证明:$$d_1(y_1, y_2, \cdots, y_k) = \sum_{x_1}^{y_1} \sum_{x_2}^{y_2} \cdots \sum_{x_k}^{y_k} d(x_1 x_2 \cdots x_k) = f_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=1}^{k} \left \lfloor \frac{y_i}{x_i} \right \rfloor \prod_{i < j} [(x_i, x_j)=1]$$
我们通过\(y_1\)来归纳:
首先\(y_1=1\)时,发现就是\(k-1\)维的证明,根据归纳条件,成立。
然后对于\(y_1 > 1\),我们设$$d_2(y_1, y_2, \cdots, y_k) = d_1(y_1, y_2, \cdots, y_k) - d_1(y_1-1, y_2, \cdots, y_k)$$ $$f_2(y_1, y_2, \cdots, y_k) = f_1(y_1, y_2, \cdots, y_k) - f_1(y_1-1, y_2, \cdots, y_k)$$然后用\(y_2\)归纳\(d_2 = f_2\)。一直这样做下去,直到需要归纳\(d_{k+1} = f_{k+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; }\]

博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。
posted @ 2015-11-22 17:56  iwtwiioi  阅读(1027)  评论(0编辑  收藏  举报