题解[SDOI2015]约数个数和

P3327 [SDOI2015]约数个数和

首先可以得出 \(d(ij)=\sum\limits_{x|i}\sum\limits_{y|j}(gcd(x,y)=1)\)

证明

首先令 \(i=p_1^{\alpha_1}p_2^{\alpha_2}...p_k^{\alpha_k},j=p_1^{\beta_1}p_2^{\beta_2}...p_k^{\beta_k}\)

那么 \(ij=p_1^{\alpha_1+\beta_1}p_2^{\alpha_2+\beta_2}...p_k^{\alpha_k+\beta_k}\)

可以得出约数个数为 \((\alpha_1+\beta_2+1)(\alpha_2+\beta_2+1)...(\alpha_k+\beta_k+1)\)

\(x|i,y|j,gcd(x,y)=1\)

可知对于每一个 \(p_i\),

\(x,y\) 可以选 \((p_i^0,p_i^0),(p_i^1,p_i^0)...(p_i^{\alpha^i},p_i^0),(p_i^0,p_i^1)...(p_i^0,p_i^{\beta^i})\)

一共是 \(\alpha^i+\beta^i+1\) 种选择

那么加起来就等于约数个数了

证毕

接下来才是重头戏

\[\sum\limits_{i=1}^n\sum\limits_{j=1}^md(ij)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(gcd(x,y)=1) \]

\(F_k=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(k|gcd(x,y)),f_k=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(gcd(x,y)=k)\)

\(F_k=\sum\limits_{k|d}f_d\)

由莫比乌斯反演可以得出 \(f_k=\sum\limits_{n|d}\mu(\frac{d}{n})F_d\)

但是到这依然不好求,考虑优化一下 \(F_k\)

\[F_k=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(k|gcd(x,y)) \]

交换一下循环顺序

\[F_k=\sum\limits_{x=1}^n\sum\limits_{y=1}^m? \]

可以得出外面两层循环的范围,那么里面两层呢?可以看出最里面的值与 \(i,j\) 无关,所以只需要考虑 \((n,m)\) 有多少个 \((i,j)\) 满足里面的条件,得出

\[F_k=\sum\limits_{x=1}^n\sum\limits_{y=1}^m\lfloor\frac{n}{x}\rfloor\lfloor\frac{m}{y}\rfloor (k|gcd(x,y)) \]

\(x`=\frac{x}{k},y`=\frac{y}{k},n`=\frac{n}{k},m`=\frac{m}{k}\),得

\[F_k=\sum\limits_{x`=1}^{n`}\sum\limits_{y`=1}^{m`}\lfloor\frac{n`}{x`}\rfloor\lfloor\frac{m`}{y`}\rfloor \]

尝试将它展开,可以得到类似于 \(a_1 b_1+a_1 b_2+...+a_1 b_n+a_2 b_1+...+a_2 b_n+...\) 的形式,等于 \((a_1+a_2+...+a_n)(b_1+b_2+...+b_n)\)

那么 \(F_k=(\sum\limits_{x`=1}^{n`}\lfloor\frac{n`}{x`}\rfloor)(\sum\limits_{y`=1}^{m`}\lfloor\frac{m`}{y`}\rfloor)\)

不妨令 \(h(x)=\sum\limits_{i=1}^x\lfloor\frac{x}{i}\rfloor\)

\[F_k=h(\frac{n}{k})h(\frac{m}{k}) \]

再代回上面的式子

\[f_k=\sum\limits_{k|d}\mu(\frac{d}{k})h(\frac{n}{d})h(\frac{m}{d}) \]

到这就很明显可以用整除分块预处理出来所有的 \(h(x)\) 和求答案了

代码

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 5e4 + 5;
typedef long long ll;

int prime[N], mu[N], sum[N], h[N], tot;
bool st[N];

int g(int k, int x)
{
    return k / (k / x);
}

void init()
{
    mu[1] = 1;
    for (int i = 2; i < N; i++)
    {
        if (!st[i])
            prime[++tot] = i, mu[i] = -1;
        for (int j = 1; prime[j] * i < N; j++)
        {
            st[i * prime[j]] = true;
            if (i % prime[j] == 0)
                break;
            mu[i * prime[j]] = -mu[i];
        }
    }
    for (int i = 1; i < N; i++)
        sum[i] = sum[i - 1] + mu[i];
    for (int i = 1; i < N; i++)
    {
        for (int l = 1, r; l <= i; l = r + 1)
        {
            r = min(i, g(i, l));
            h[i] += (r - l + 1) * (i / l);
        }
    }
}

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

posted @ 2021-04-18 21:56  DSHUAIB  阅读(55)  评论(0编辑  收藏  举报