题目描述

设d(x)d(x)d(x)为xxx的约数个数,给定NNN、MMM,求 ∑i=1N∑j=1Md(ij)\sum^{N}_{i=1}\sum^{M}_{j=1} d(ij)i=1∑N​j=1∑M​d(ij)

N,M,T&lt;=50000N,M,T&lt;=50000N,M,T<=50000

题目分析

首先很不显然的有这样一个结论:

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

证明如下

将一个数唯一质因数分解为p1k1p2k2p3k3...pnknp_1^{k_1}p_2^{k_2}p_3^{k_3}...p_n^{k_n}p1k1​​p2k2​​p3k3​​...pnkn​​,其约数个数为(k1+1)(k2+1)(k3+1)...(kn+1)(k_1+1)(k_2+1)(k_3+1)...(k_n+1)(k1​+1)(k2​+1)(k3​+1)...(kn​+1)

考虑一个质数ppp对d(ij)d(ij)d(ij)的影响,假设iii分解质因数后有kkk个ppp,jjj分解质因数后有qqq个ppp,则产生的贡献即为k+q+1k+q+1k+q+1,接下来是关键的一步(反正我想不到XD)

k+q+1=∑x=0k∑y=0q[(px,py)==1]k+q+1=\sum_{x=0}^k\sum_{y=0}^q[(p^x,p^y)==1]k+q+1=x=0∑k​y=0∑q​[(px,py)==1]

(此句可自行忽略:只有当xy=0xy=0xy=0时才会有值,这就相当于一个(k+1)∗(q+1)(k+1)∗(q+1)(k+1)∗(q+1)的矩形,只取了左下角的LLL字型的一块)

根据乘法原理,有

d(ij)=∑x1=0k1∑y1=0q1[(p1x1,p1y1)==1]∗∑x2=0k2∑y2=0q2[(p2x2,p2y2)==1]⋅⋅⋅∗∑xn=0kn∑yn=0qn[(pnxn,pnyn)==1]
d(ij)=\sum_{x_1=0}^{k_1}\sum_{y_1=0}^{q_1}[(p_1^{x_1},p_1^{y_1})==1]\newline
*\sum_{x_2=0}^{k_2}\sum_{y_2=0}^{q_2}[(p_2^{x_2},p_2^{y_2})==1]\newline
···\newline
*\sum_{x_n=0}^{k_n}\sum_{y_n=0}^{q_n}[(p_n^{x_n},p_n^{y_n})==1]
d(ij)=x1​=0∑k1​​y1​=0∑q1​​[(p1x1​​,p1y1​​)==1]∗x2​=0∑k2​​y2​=0∑q2​​[(p2x2​​,p2y2​​)==1]⋅⋅⋅∗xn​=0∑kn​​yn​=0∑qn​​[(pnxn​​,pnyn​​)==1]

因为必须满足所有(pnxn,pnyn)==1(p_n^{x_n},p_n^{y_n})==1(pnxn​​,pnyn​​)==1才会对答案造成贡献,则可以变形为(∏i=1npnxn,∏i=1npnyn)==1(\prod_{i=1}^np_n^{x_n},\prod_{i=1}^np_n^{y_n})==1(i=1∏n​pnxn​​,i=1∏n​pnyn​​)==1

所以d(ij)=∑x∣i∑y∣j[(x,y)==1]d(ij)=\sum_{x|i}\sum_{y|j}[(x,y)==1]d(ij)=x∣i∑​y∣j∑​[(x,y)==1]

(以上证明摘自:传送门)

证毕

现在就有了Ans=∑i=1N∑j=1M∑x∣i∑y∣j[(x,y)==1]Ans=\sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}^{}\sum_{y|j}^{}[(x,y)==1]Ans=i=1∑N​j=1∑M​x∣i∑​y∣j∑​[(x,y)==1]

根据数论中切换枚举次序的套路以及莫比乌斯反演对布尔条件框的替换,我们得到

Ans=∑x=1N∑y=1M⌊Nx⌋⌊My⌋[(x,y)==1]=∑x=1N∑y=1M⌊Nx⌋⌊My⌋∑k∣(x,y)μ(k)=∑k=1min(N,M)μ(k)∑k∣x⌊Nx⌋∑k∣y⌊My⌋=∑k=1min(N,M)μ(k)∑x=1⌊Nk⌋⌊Nkx⌋∑y=1⌊Mk⌋⌊Mky⌋
Ans=\sum_{x=1}^{N}\sum_{y=1}^{M}⌊\frac{N}{x}⌋⌊\frac{M}{y}⌋[(x,y)==1]\newline
=\sum_{x=1}^{N}\sum_{y=1}^{M}⌊\frac{N}{x}⌋⌊\frac{M}{y}⌋\sum_{k|(x,y)}\mu(k)\newline
=\sum_{k=1}^{min(N,M)}\mu(k)\sum_{k|x}^{}⌊\frac{N}{x}⌋\sum_{k|y}^{}⌊\frac{M}{y}⌋\newline
=\sum_{k=1}^{min(N,M)}\mu(k)\sum_{x=1}^{⌊\frac{N}{k}⌋}⌊\frac{N}{kx}⌋\sum_{y=1}^{⌊\frac{M}{k}⌋}⌊\frac{M}{ky}⌋
Ans=x=1∑N​y=1∑M​⌊xN​⌋⌊yM​⌋[(x,y)==1]=x=1∑N​y=1∑M​⌊xN​⌋⌊yM​⌋k∣(x,y)∑​μ(k)=k=1∑min(N,M)​μ(k)k∣x∑​⌊xN​⌋k∣y∑​⌊yM​⌋=k=1∑min(N,M)​μ(k)x=1∑⌊kN​⌋​⌊kxN​⌋y=1∑⌊kM​⌋​⌊kyM​⌋

于是这里使用分块优化,预处理μ\muμ的前缀和

最后考虑后面的两个Sigma怎么处理

可以观察发现它们都是∑i=1n⌊ni⌋\sum_{i=1}^{n}⌊\frac{n}{i}⌋∑i=1n​⌊in​⌋的形式,此处可以用分块优化Θ(nn)\Theta(n\sqrt{n})Θ(nn​)预处理

其实还可以Θ(n)\Theta(n)Θ(n)预处理,可以发现∑i=1n⌊ni⌋=∑i=1n∑i∣dn1\sum_{i=1}^{n}⌊\frac{n}{i}⌋=\sum_{i=1}^{n}\sum_{i|d}^{n}1∑i=1n​⌊in​⌋=∑i=1n​∑i∣dn​1

显然是约数个数和d(n)d(n)d(n)的前缀和函数,于是线性筛出μ(n)\mu(n)μ(n)与d(n)d(n)d(n),求出前缀和即可

每次询问Θ(n)\Theta(\sqrt{n})Θ(n​), 预处理Θ(n)\Theta(n)Θ(n),总时间复杂度为Θ(nn)\Theta(n\sqrt{n})Θ(nn​)

TIPS

线性筛约数个数时存一下最小的质数p1p_1p1​的次方+1+1+1,即存下(k1+1)(k_1+1)(k1​+1)就可以方便的线性筛了

线性筛约数和同理,存一下最小的质数p1p_1p1​所对应的首项为111,公比为p1p_1p1​,项数为k1+1k_1+1k1​+1的等比数列,即存下∑i=1k1p1i\sum_{i=1}^{k_1}p_1^i∑i=1k1​​p1i​就可以愉快的线性筛了

AC code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int MAXN = 100001;
namespace Mobius
{
#define LL long long
int Prime[MAXN], Cnt, mu[MAXN], d[MAXN], Minseq[MAXN];
bool IsnotPrime[MAXN];
LL sum_MU[MAXN], sum_D[MAXN];
void init()
{
mu[1] = d[1] = Minseq[1] = 1;
for(int i = 2; i < MAXN; ++i)
{
if(!IsnotPrime[i])
Prime[++Cnt] = i, mu[i] = -1, d[i] = Minseq[i] = 2;
for(int j = 1; j <= Cnt && i * Prime[j] < MAXN; ++j)
{
IsnotPrime[i * Prime[j]] = 1;
if(i % Prime[j] == 0)
{
Minseq[i * Prime[j]] = Minseq[i]+1;
mu[i * Prime[j]] = 0;
d[i * Prime[j]] = d[i] / Minseq[i] * Minseq[i * Prime[j]];
break;
}
Minseq[i * Prime[j]] = 2;
mu[i * Prime[j]] = -mu[i];
d[i * Prime[j]] = d[i]<<1;
}
}
for(int i = 1; i < MAXN; ++i)
sum_MU[i] = sum_MU[i-1] + mu[i],
sum_D[i] = sum_D[i-1] + d[i];
}
LL calc(int N, int M)
{
if(N > M) swap(N, M);
LL ret = 0;
for(int i = 1, j; i <= N; i=j+1)
{
j = min(N/(N/i), M/(M/i));
ret += (sum_MU[j]-sum_MU[i-1]) * sum_D[N/i] * sum_D[M/i];
}
return ret;
}
}
using namespace Mobius;
int main ()
{
init();
int T, n, m;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
printf("%lld\n", calc(n, m));
}
}

[SDOI2015][bzoj 3994][Luogu P3327] 约数个数和 (莫比乌斯反演)的更多相关文章

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

    P3327 [SDOI2015]约数个数和 莫比乌斯反演 链接 luogu 思路 第一个式子我也不会,luogu有个证明,自己感悟吧. \[d(ij)=\sum\limits_{x|i}\sum\li ...

  2. BZOJ 3994: [SDOI2015]约数个数和 [莫比乌斯反演 转化]

    2015 题意:\(d(i)\)为i的约数个数,求\(\sum\limits_{i=1}^n \sum\limits_{j=1}^m d(ij)\) \(ij\)都爆int了.... 一开始想容斥一下 ...

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

    题面 我的做法基于以下两个公式: \[[n=1]=\sum_{d|n}\mu(d)\] \[\sigma_0(i*j)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\] 其中\(\ ...

  4. BZOJ 3994: [SDOI2015]约数个数和3994: [SDOI2015]约数个数和 莫比乌斯反演

    https://www.lydsy.com/JudgeOnline/problem.php?id=3994 https://blog.csdn.net/qq_36808030/article/deta ...

  5. [BZOI 3994] [SDOI2015]约数个数和(莫比乌斯反演+数论分块)

    [BZOI 3994] [SDOI2015]约数个数和 题面 设d(x)为x的约数个数,给定N.M,求\(\sum _{i=1}^n \sum_{i=1}^m d(i \times j)\) T组询问 ...

  6. 洛谷P3327 [SDOI2015]约数个数和(莫比乌斯反演)

    题目描述 设d(x)为x的约数个数,给定N.M,求 \sum^N_{i=1}\sum^M_{j=1}d(ij)∑i=1N​∑j=1M​d(ij) 输入输出格式 输入格式: 输入文件包含多组测试数据.第 ...

  7. 【BZOJ3994】[SDOI2015]约数个数和 莫比乌斯反演

    [BZOJ3994][SDOI2015]约数个数和 Description  设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组 ...

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

    题面: 传送门 思路: 首先,我们需要证明一个结论:d(i*j)等于sigma(gcd(x,y)==1),其中x为i的约数,y为j的约数 对于nm的每一个质因子pi分别考虑,设n = pi^ai + ...

  9. BZOJ3994: [SDOI2015]约数个数和(莫比乌斯反演)

    Description  设d(x)为x的约数个数,给定N.M,求     Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Out ...

随机推荐

  1. 关于epoll,select,poll的理解

    select: 轮询+fd_set 1.采用fd_set存储fd(fd_set通过数组位图实现) 2.每次调用select,都需要把fd集合从用户态拷贝到内核态,fd越多开销越大 3.每次调用sele ...

  2. 025 Android 带进度条的对话框(ProgressDialog)

    1.ProgressDialog介绍 ProgressDialog可以在当前界面弹出一个置顶于所有界面元素的对话框,同样具有屏蔽其他控件的交互能力,用于提示用户当前操作正在运行,让用户等待: 2.应用 ...

  3. [转帖]Linux文件系统详解

    Linux文件系统详解 https://www.cnblogs.com/alantu2018/p/8461749.html 贼复杂.. 从操作系统的角度详解Linux文件系统层次.文件系统分类.文件系 ...

  4. 如何理解MVC

    在面试的时候,MVC这个概念考的次数很多,有许多人只能把三个字母解释成三个单词:model,view,controller,但是如果往深处说就说不出来什么东西了,对这个概念模糊不清,今天闲来无事看了一 ...

  5. 字典的学习3——嵌套——Python编程从入门到实践

    嵌套 ? 一系列字典存储在列表or列表作为值存储在字典or字典中套字典 1. 字典列表 alien_0 = {'color': 'green', 'points': 5} alien_1 = {'co ...

  6. python 之 前端开发(HTTP协议、head标签、img标签、a标签、列表标签)

    第十一章前端开发 11.1 HTTP 1.1引入了许多关键性能优化:keepalive连接,请求流水线,chunked编码传输,字节范围请求等 1.keepalive连接: 1.长连接允许HTTP设备 ...

  7. TZOJ3133: 求对称点

    #include<stdio.h> int main() { double a,b,c,d,e,f,g,h,i; while(~scanf("%lf %lf %lf %lf %l ...

  8. 使用VS2012编译和使用C++ STL(STLport)

    使用VS2012编译和使用C++ STL(STLport) http://cstriker1407.info/blog/use-vs2012-to-compile-and-use-the-c-stl- ...

  9. https、加密安全

    1.Https HTTPS在传输的过程中会涉及到三个密钥: 服务器端的公钥和私钥,用来进行非对称加密 客户端生成的随机密钥,用来进行对称加密 一个HTTPS请求实际上包含了两次HTTP传输,可以细分为 ...

  10. git pull 的时候 把本地的修改 覆盖远程端

    首先,git pull 可以分成两步,git fetch 和git merge 使用git branch -a可以看出来    git merge 相当于当前分支  和 origin/master分支 ...