洛谷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 = \sum_{i = 1}^{N} \sum_{j = 1}^{M} d(ij)\)

有一个这样的结论:

\(d(ij) = \sum_{x|i}\sum_{y|j} [gcd(x,y) == 1]\)

那么就转化为了:

\(ans =\sum_{i = 1}^{N} \sum_{j = 1}^{M} \sum_{x|i}\sum_{y|j} [gcd(x,y) == 1]\)

我们考虑对于每一对互质的x、y,x会被枚举\(\lfloor \frac{N}{x} \rfloor\)次,y会被枚举\(\lfloor \frac{M}{y} \rfloor\)次

所以有

\(ans =\sum_{i = 1}^{N} \sum_{j = 1}^{M} \lfloor \frac{N}{i} \rfloor \lfloor \frac{M}{j} \rfloor [gcd(i,j) == 1]\)

那么可以进行莫比乌斯反演了

\(f(n) = \sum_{i = 1}^{N} \sum_{j = 1}^{M} \lfloor \frac{N}{i} \rfloor \lfloor \frac{M}{j} \rfloor [gcd(i,j) == n]\)

\(F(n) = \sum_{i = 1}^{N} \sum_{j = 1}^{M} \lfloor \frac{N}{i} \rfloor \lfloor \frac{M}{j} \rfloor [n | gcd(i,j)]\)

那么有

\(F(n) = (\sum_{i = 1}^{N}\lfloor \frac{N}{i} \rfloor) * (\sum_{j = 1}^{M} \lfloor \frac{M}{j} \rfloor) [n | gcd(i,j)]\)

其中\(\sum_{i = 1}^{N}\lfloor \frac{N}{i} \rfloor\)可以\(O(n\sqrt{n})\)预处理出,我们记为\(sum(n)\)

\(ans = f(1) = \sum_{d = 1}^{N} \mu(d) * F(d) = \sum_{d} \mu(d) sum(\lfloor \frac{N}{d} \rfloor) * sum(\lfloor \frac{M}{d} \rfloor)\)

分块计算

复杂度\(O(T\sqrt{N} + N\sqrt(N))\)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 50005,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - ‘0‘; c = getchar();}
    return out * flag;
}
int prime[maxn],primei,mu[maxn],isn[maxn];
LL sum[maxn];
void init(){
    mu[1] = 1;
    for (int i = 2; i < maxn; i++){
        if (!isn[i]) prime[++primei] = i,mu[i] = -1;
        for (int j = 1; j <= primei && i * prime[j] < maxn; j++){
            isn[i * prime[j]] = true;
            if (i % prime[j] == 0){mu[i * prime[j]] = 0; break;}
            mu[i * prime[j]] = -mu[i];
        }
    }
    for (int i = 1; i < maxn; i++) mu[i] += mu[i - 1];
    for (int n = 1,nxt; n <= 50000; n++){
        for (int i = 1; i <= n; i = nxt + 1){
            nxt = n / (n / i);
            sum[n] += (LL)(nxt - i + 1) * (n / i);
        }
    }
}
int main(){
    init();
    int T = read(),n,m;
    while (T--){
        n = read(); m = read();
        if (n > m) swap(n,m);
        LL ans = 0; int nxt;
        for (int i = 1; i <= n; i = nxt + 1){
            nxt = min(n / (n / i),m / (m / i));
            ans += sum[n / i] * sum[m / i] * (mu[nxt] - mu[i - 1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8361823.html

时间: 2024-10-28 19:37:40

洛谷P3327 [SDOI2015]约数个数和 【莫比乌斯反演】的相关文章

洛谷P3327 [SDOI2015]约数个数和

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

luogu P3327 [SDOI2015]约数个数和 莫比乌斯反演

题面 我的做法基于以下两个公式: \[[n=1]=\sum_{d|n}\mu(d)\] \[\sigma_0(i*j)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\] 其中\(\sigma_0(n)\)表示\(n\)的约数个数 第一个公式是莫比乌斯函数的基本性质,至于第二个公式的证明,可以考虑\(i*j\)中每一个质因子对 \(\sigma_0(i*j)\) 的贡献,对于一个质因子 \(p\) ,若它在 \(i\) 中的次数为 \(k_1\) ,它在 \(j\) 中的次数为

[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\

【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

BZOJ 3994 Sdoi2015 约数个数和 莫比乌斯反演

题目大意:求∑ni=1∑mj=1d(ij) 首先我们有一个很神的结论: ∑ni=1∑mj=1d(ij)=∑ni=1∑mj=1?ni??mj?[gcd(i,j)==1] 这个结论是怎么来的呢?我们可以先证明这个: d(nm)=∑i|n∑j|m1?1[gcd(i,j)==1] 显然这个式子的前缀和就是上面的式子 现在我们来证明这个式子是对的 我们分开讨论每一个质数p对答案的贡献 不妨设n=n′?pk1,m=m′?pk2 那么左式中p的贡献显然是k1+k2+1 右式中只考虑p的话,满足要求的数对(i,

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

题面: 传送门 思路: 首先,我们需要证明一个结论:d(i*j)等于sigma(gcd(x,y)==1),其中x为i的约数,y为j的约数 对于nm的每一个质因子pi分别考虑,设n = pi^ai + n',m = pi^bi + m' 那么显然质因子pi对d(nm)的贡献为(ai+bi+1) 同理,考虑右边的式子,我们发现质数pi对右侧做的贡献仍然是(ai+bi+1),即如下的(x,y) (pi^ai,1) (pi^(ai-1),1) ..... (1,1) .....(1,pi^(bi-1))

P3327 [SDOI2015]约数个数和

传送门 首先证明 $d(ij)=\sum_{k|i}\sum_{l|j}[gcd(k,l)==1]$ 把 $i,j$ 考虑成唯一分解后的形式:$P_{i1}^{k1}P_{i2}^{k2}...P_{in}^{kn}$ 对于 $i,j$ 中某个相同的质因子 $P_{x}$ ,$i=...P_{x}^{ki}...$,$j=...P_{x}^{kj}...$ 如果枚举到 $j$ 中因数 $l$ 时,$l$ 有因数 $P_{x}^{t}$,不妨看成 $P_{x}^{ki+t}$, 如果这样看,那么会

[BZOJ 3994]约数个数和 莫比乌斯反演

自己是在是弱,看了半天才看懂题解 写公式实在是麻烦,搬家一份: #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define N 101000 #define pos(i,a,b) for(int i=(a);i<=(b);i++) using namespace std; #define LL long long int t,n,m; int notpr

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