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

我们用\(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;
}

转载于:https://www.cnblogs.com/iwtwiioi/p/4986325.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值