题面

求\(\sum_{i=1}^n\sum_{j=1}^md(ij)\)

\(\leq 50000\)组数据,\(1\leq n,m\leq 50000\)。

题目分析

首先,你需要知道一个结论:

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

你可以认为\(x,y\)表示你选择的因数为\(\frac i x \cdot y\),即:\(x\)表示\(i\)中不要的部分,\(y\)表示\(j\)中要的部分。

如果\(gcd(x,y)==p_i\),那么\(\frac i x\)表示在约数中拿掉\(p_i\),\(y\)表示在约数中加入\(p_i\),这样一拿一加,自然会在答案中重复。


那么,现在我们的问题转化为求

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

这样还是无法计算,所以我们把枚举因数提前

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

现在看起来就可以反演了,设\(f(x)\)表示\(gcd(i,j)==x\)时的答案,\(g(x)\)表示\(gcd(i,j)==kx,k\in Z\)时的答案,则:

\[\begin{split}
f(x)&=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\lfloor\frac n i\rfloor\lfloor\frac m j\rfloor[gcd(i,j)==x]\\
g(x)&=\sum\limits_{x|d}^nf(d)\\
&=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\lfloor\frac n i\rfloor\lfloor\frac m j\rfloor[x|gcd(i,j)]\\
&=\sum\limits_{i=1}^{\lfloor\frac n x\rfloor}\sum\limits_{j=1}^{\lfloor\frac m x\rfloor}\lfloor\frac n {ix}\rfloor\lfloor\frac m {jx}\rfloor\\
&=\sum\limits_{i=1}^{\lfloor\frac n x\rfloor}\lfloor\frac n {ix}\rfloor\sum\limits_{j=1}^{\lfloor\frac m x\rfloor}\lfloor\frac m {jx}\rfloor
\end{split}
\]


比较巧的一点是:\(\sum\limits_{i=1}^n\lfloor\frac n i\rfloor\)可以表示\(1 \sim n\)的约数个数的前缀和。

约数个数可以在线性筛中预处理,原理如下:

对于\(x=p_1^{a_1}p_2^{a_2}p_3^{a_3}...p_n^{a_n}\),\(x\)的约数个数为\((a_1+1)\cdot(a_2+1)\cdot(a_3+1)\cdot...\cdot(a_n+1)\)

由于在线性筛中,每个数只会被它最小的质因子更新,所以:

如果\(i\%prime[j]==0\),说明\(i\)中含有\(prime[j]\),此时\(x\)中\(prime[j]\)的个数为\(i\)中\(prime[j]\)的个数\(+1\),\(x\)的约数个数=\(i\)的约数个数/(\(i\)中\(prime[j]\)的个数)*(\(i\)中\(prime[j]\)的个数\(+1\));

如果\(i\%prime[j]!=0\),说明\(prime[j]\)在\(x\)中只有\(1\)个,\(x\)的约数个数=\(i\)的约数个数*\(2\)。


这样一来\(g(x)\)可以进行预处理,然后\(O(1)\)计算。

反演得\(f(x)=\sum\limits_{x|d}^n\mu(\frac dx)g(d)\),为了针对多组数据,整除分块即可。

代码实现

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#define MAXN 0x7fffffff
typedef long long LL;
const int N=50005;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
int mu[N],prime[N];
bool vis[N]; int ys[N],lw[N],g[N];
int main(){
mu[1]=g[1]=1;
for(int i=2;i<=50000;i++){
if(!vis[i])prime[++prime[0]]=i,mu[i]=-1,ys[i]=2,lw[i]=1;
for(int j=1;j<=prime[0]&&i*prime[j]<=50000;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0){
ys[i*prime[j]]=ys[i]/(lw[i]+1)*(lw[i]+2);
lw[i*prime[j]]=lw[i]+1;
break;
}
mu[i*prime[j]]=-mu[i];
ys[i*prime[j]]=ys[i]*2,lw[i*prime[j]]=1;
}
mu[i]+=mu[i-1],g[i]=g[i-1]+ys[i];
} int T=Getint();
while(T--){
int n=Getint(),m=Getint();
if(n>m)swap(n,m);
LL ans=0;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=1ll*(mu[r]-mu[l-1])*g[n/l]*g[m/l];
}
cout<<ans<<'\n';
}
return 0;
}

【SDOI2015】约数个数和的更多相关文章

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

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

  2. P3327/bzoj3994 [SDOI2015]约数个数和(莫比乌斯反演)

    P3327 [SDOI2015]约数个数和 神犇题解(转) 无话可补 #include<iostream> #include<cstdio> #include<cstri ...

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

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

  4. 洛谷 [SDOI2015]约数个数和 解题报告

    [SDOI2015]约数个数和 题目描述 设\(d(x)\)为\(x\)的约数个数,给定\(N,M\),求$ \sum\limits^N_{i=1}\sum\limits^M_{j=1}d(ij)$ ...

  5. BZOJ 3994: [SDOI2015]约数个数和

    3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 898  Solved: 619[Submit][Statu ...

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

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

  7. 洛谷P3327 - [SDOI2015]约数个数和

    Portal Description 共\(T(T\leq5\times10^4)\)组数据.给出\(n,m(n,m\leq5\times10^4)\),求\[\sum_{i=1}^n\sum_{j= ...

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

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

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

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

  10. 【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} ...

随机推荐

  1. Java 网络编程(1):使用 NetworkInterface 获得本机在局域网内的 IP 地址

    原文地址:https://segmentfault.com/a/1190000007462741 1.问题提出 在使用 Java 开发网络程序时,有时候我们需要知道本机在局域网中的 IP 地址.很常见 ...

  2. 3. Image Structure and Generation

    名词 Extensible Linking Format(ELF) 3.1 The structure of an ARM ELF image ARM ELF映像包含sections, regions ...

  3. Android Telephony分析(五) ---- TelephonyRegistry详解

    本文紧接着上一篇文章<Android Telephony分析(四) —- TelephonyManager详解 >的1.4小节.从TelephonyRegistry的大部分方法中: 可以看 ...

  4. markdown转为pdf文件

    要求: 把.md格式转为.pdf格式,并批量处理,最后将多个pdf文件合并为一个pdf并以文件名作为书签名 解决思路: 1.md格式的markdown文件转为html 为了将 md 格式转换成 htm ...

  5. HDU 4325 离散化+树状数组 或者 不使用树状数组

    题意:给出一些花的开放时间段,然后询问某个时间点有几朵花正在开放. 由于ti<1e9,我们需要先将时间离散化,然后将时间点抽象为一个数组中的点,显然,我们需要进行区间更新和单点查询,可以考虑线段 ...

  6. 字符串KMP算法

    讲解:http://blog.csdn.net/starstar1992/article/details/54913261 #include <bits/stdc++.h> using n ...

  7. 在CentOS 7上安装常用的YUM源

    参考地址:https://blog.csdn.net/u010048823/article/details/51298183 以epel源为例子,来讲解如何添加额外的YUM源. Extra Packa ...

  8. Flask-session用法

    概念 flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持session保存到多个地方,如: * redis:保 ...

  9. CSIC_716_20191118【常用模块的用法 Json、pickle、collections、openpyxl】

    序列化模块 序列化:将python或其他语言中的数据类型,转变成字符串类型. python中的八大数据类型回顾:int float str list tuple dict set bool 反序列化: ...

  10. WPF命令好状态刷新机制

    https://blog.csdn.net/WPwalter/article/details/90344470 this.DispatcherInvoke(() => { System.Wind ...