Sdoi2015约数个数和题解莫比乌斯反演

题目描述

  • T组数据,求ΣNi=1ΣMj=1d(ij),d(x)代表x的约数个数。
  • 1≤N,M,T≤105

题解

  • 首先,膜拜一下PoPoQQQ大神及其题解
  • 然后,有一个神奇的结论:ΣNi=1ΣMj=1d(ij)=ΣNi=1ΣMj=1[Ni][Mj][gcd(i,j)=1]

    要证上式,只需证d(nm)=Σi|nΣj|m[gcd(i,j)=1],因为上式即为该式的前缀和形式。

    分开考虑每个质数p对答案的贡献。设n=n′pk1,m=m′pk2,那p对d(nm)的贡献就是k1+k2+1,对等式右边的贡献是有序数对(i,j)中的(pk1,1)(pk1?1,1)(pk1?2,1)…(1,1)(1,p)…(1,pk2?1)(1,pk2)也是k1+k2+1,所以原式得证。

  • 再令f(x)=Σxi=1[xi],显然有f(x)=d(x),因为f(x)相当于把i=1→x对d(x)的贡献求和,就是d(x)本身
  • 然后可以莫比乌斯反演了:

    ans=ΣNi=1ΣMj=1[Ni][Mj][gcd(i,j)=1]=ΣNi=1ΣMj=1Σk|gcd(i,j)μ(k)[Ni][Mj]=ΣNk=1Σ[Nk]i=1Σ[Mk]j=1μ(k)[Nki][Mkj]=ΣNk=1μ(k)Σ[Nk]i=1[Nki]Σ[Mk]j=1[Nkj]=ΣNk=1μ(k)f([Mk])f([Mk])=ΣNk=1μ(k)d([Nk])d([Mk])

  • 然后用筛法筛出μ(i)和d(i)再做就好了。
  • 看来还需要锻炼自己的数学功底啊

Code

#include <cstdio>
#include <algorithm>
#define ll long long
#define M 50000
using namespace std;
int mu[M + 5], n, m, pri[M], top, d[M + 5], f[M + 5];
bool mrk[M + 5];
void getmu()
{
    mu[1] = d[1] = 1;
    for(int i = 2; i <= M; ++i)
    {
        if(!mrk[i])
        {
            pri[top++] = i;
            mu[i] = -1;
            d[i] = 2;
            f[i] = 1;
        }
        for(int j = 0; j < top && i * pri[j] <= M; ++j)
        {
            mrk[i * pri[j]] = true;
            if(i % pri[j] == 0)
            {
                mu[i * pri[j]] = 0;
                f[i * pri[j]] = f[i] + 1;
                d[i * pri[j]] = d[i] / (f[i] + 1) * (f[i] + 2);
                break;
            }
            mu[i * pri[j]] = -mu[i];
            d[i * pri[j]] = (d[i] << 1);
            f[i * pri[j]] = 1;
        }
    }
    for(int i = 2; i <= M; ++ i)
    {
        d[i] += d[i - 1];
        mu[i] += mu[i - 1];
    }
}
inline ll work(int n, int m)
{
    if(n > m) swap(n, m);
    ll ans = 0;
    for(int i = 1, j; i <= n; i = j + 1)
    {
        j = min(n / (n / i), m / (m / i));
        ans += (ll)(mu[j] - mu[i - 1]) * (ll)d[n / i] * (ll)d[m / i];
    }
    return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("d.txt", "r", stdin);
    freopen("a.txt", "w", stdout);
#endif
    int T;
    getmu();
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &n, &m);
        printf("%lld\n", work(n, m));
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-02 03:43:06

Sdoi2015约数个数和题解莫比乌斯反演的相关文章

【BZOJ 3994】3994: [SDOI2015]约数个数和(莫比乌斯反演)

3994: [SDOI2015]约数个数和 Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7 4 5 6 Sample Output 110 121 HINT 1<=N, M<=50000 1<=T<=50000 Source Round 1 感谢yts199

洛谷P3327 [SDOI2015]约数个数和 【莫比乌斯反演】

题目 设d(x)为x的约数个数,给定N.M,求\(\sum_{i = 1}^{N} \sum_{j = 1}^{M} d(ij)\) 输入格式 输入文件包含多组测试数据.第一行,一个整数T,表示测试数据的组数.接下来的T行,每行两个整数N.M. 输出格式 T行,每行一个整数,表示你所求的答案. 输入样例 2 7 4 5 6 输出样例 110 121 提示 1<=N, M<=50000 1<=T<=50000 题解 好神的题[是我太弱吧] 首先上来就伤结论.. 题目所求 \(ans

BZOJ_3994_[SDOI2015]约数个数和_莫比乌斯反演

Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7 4 5 6 Sample Output 110 121 HINT 1<=N, M<=50000 1<=T<=50000 基本同BZOJ4176,需要处理$f_n=\sum\limits_{i=1}n/i$,然后

【bzoj3994】[SDOI2015]约数个数和 莫比乌斯反演

题目描述 设d(x)为x的约数个数,给定N.M,求   输入 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. 输出 T行,每行一个整数,表示你所求的答案. 样例输入 2 7 4 5 6 样例输出 110 121 题解 莫比乌斯反演 根据 bzoj4176 推出的结论, 那么就有: 预处理mu及其前缀和. 由于要处理多组询问,所以需要用O(n√n)的时间预处理出f,然后对于每组询问分块来求. #include <cstdio> #incl

[SDOI2015] 约数个数和 (莫比乌斯反演)

[SDOI2015]约数个数和 题目描述 设d(x)为x的约数个数,给定N.M,求 \(\sum^N_{i=1}\sum^M_{j=1}d(ij)\) 输入输出格式 输入格式: 输入文件包含多组测试数据.第一行,一个整数T,表示测试数据的组数.接下来的T行,每行两个整数N.M. 输出格式: T行,每行一个整数,表示你所求的答案. 输入输出样例 输入样例#1: 2 7 4 5 6 输出样例#1: 110 121 说明 \(1<=N, M<=50000\) \(1<=T<=50000\

BZOJ 3994 [SDOI2015]约数个数和 (神定理+莫比乌斯反演)

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit:128 MB Submit: 239  Solved: 176 [Submit][Status][Discuss] Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7

BZOJ 3994: [SDOI2015]约数个数和

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 898  Solved: 619[Submit][Status][Discuss] Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7

3994: [SDOI2015]约数个数和

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 858  Solved: 587[Submit][Status][Discuss] Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7

[BZOI 3994] [SDOI2015]约数个数和

[BZOI 3994] [SDOI2015]约数个数和 题面 设d(x)为x的约数个数,给定N.M,求\(\sum _{i=1}^n \sum_{i=1}^m d(i \times j)\) T组询问,\(N,M,T \leq 50000\) 分析 首先有一个结论 \[d(nm)= \sum _{i |n} \sum _{j|m} [gcd(i,j)=1]\] 这是因为nm的约数都可以表示为\(i \times \frac{m}{j}\)的形式,并且为了不重复算,要保证\(gcd(i,j)=1\