P3327 [SDOI2015]约数个数和
Posted tongseli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3327 [SDOI2015]约数个数和相关的知识,希望对你有一定的参考价值。
题目描述
设d(x)为x的约数个数,给定N、M,求 \(\sum\limits^N_{i=1}\sum\limits^M_{j=1}d(ij)\)
输入格式
输入文件包含多组测试数据。第一行,一个整数T,表示测试数据的组数。接下来的T行,每行两个整数N、M。
输出格式
T行,每行一个整数,表示你所求的答案。
说明/提示
1<=N, M<=50000
1<=T<=50000
输入输出样例
输入
2
7 4
5 6
输出
110
121
首先,需要知道一个公式
\[d(ij)=\sum\limits_{x|i}\sum\limits_{y|j}[\gcd(x,y)==1]\]
可以简单的意会一下这个公式。
我们对\(i\) 质因数分解,\(i=\prod\limits_{t}p_t^{\alpha_t}\) ,同样地,对\(j\) 质因数分解,\(j=\prod\limits_{t}p_t^{\beta_t}\)
我们显然知道,\(d(i)=\prod\limits_{t}(\alpha_t+1)\) ,\(d(i)=\prod\limits_{t}(\beta_t+1)\)
回到题目,\(ij=\prod\limits_{t}p_t^{\alpha_t+\beta_t}\) ,于是 \(d(ij)=\prod\limits_{t}(\alpha_t+\beta_t+1)\)
我们考虑直接这样枚举:\(\sum\limits_{x|i}\sum\limits_{y|j}1\)
这样就枚举多了...超过了\(\alpha_t+\beta_t+1\) ...
事实上,我们只需要考虑,\(ij\) 每个质因子\(p_t\) 被计算了几次(它应该被枚举\(\alpha_t+\beta_t\)次)。
不难发现,我们只要保证\(\gcd(x,y)==1\),就可以在\(p|a\) 的时候被枚举\(\alpha_t\) 次,在\(p|b\) 时枚举\(\beta_t\) 次。
所以就是
\[d(ij)=\sum\limits_{x|i}\sum\limits_{y|j}[\gcd(x,y)==1]\]
本题是求
\[\sum\limits^N_{i=1}\sum\limits^M_{j=1}d(ij)\]
代入公式,可以有
\[\sum\limits^N_{i=1}\sum\limits^M_{j=1}\sum\limits_{x|i}\sum\limits_{y|j}[\gcd(x,y)==1]\]
\[\sum\limits^N_{i=1}\sum\limits_{x|i}1\sum\limits^M_{j=1}\sum\limits_{y|j}1\cdot[\gcd(x,y)==1]\]
更换一下枚举顺序
\[\sum\limits^N_{x=1}\lfloor\frac{N}{x}\rfloor\sum\limits^M_{y=1}\lfloor\frac{M}{y}\rfloor\cdot[\gcd(x,y)==1]\]
\[\sum\limits^N_{x=1}\sum\limits^M_{y=1}[\gcd(x,y)==1]\cdot\lfloor\frac{N}{x}\rfloor\lfloor\frac{M}{y}\rfloor\]
用一下\(I=\mu *u\)
\[\sum\limits^N_{x=1}\sum\limits^M_{y=1}\sum\limits_{d|gcd(x,y)}\mu(d)\cdot\lfloor\frac{N}{x}\rfloor\lfloor\frac{M}{y}\rfloor\]
改成枚举
\[\sum\limits^N_{x=1}\sum\limits^M_{y=1}\sum\limits_{d=1}^{\min(N,M)}[d|gcd(x,y)]\mu(d)\cdot\lfloor\frac{N}{x}\rfloor\lfloor\frac{M}{y}\rfloor\]
\[\sum\limits_{d=1}^{\min(N,M)}\mu(d)\sum\limits^N_{x=1}\sum\limits^M_{y=1}[d|gcd(x,y)]\cdot\lfloor\frac{N}{x}\rfloor\lfloor\frac{M}{y}\rfloor\]
更换一下枚举到东西,本来是枚举\(x,y\),现在枚举\(dx,dy\) ,这样肯定会被整除!
\[\sum\limits_{d=1}^{\min(N,M)}\mu(d)\sum\limits^{N/d}_{x=1}\sum\limits^{M/d}_{y=1}\lfloor\frac{N}{dx}\rfloor\lfloor\frac{M}{dy}\rfloor\]
此时,我们就得到最终的式子
\[\sum\limits_{d=1}^{\min(N,M)}\mu(d)\sum\limits^{N/d}_{x=1}\lfloor\frac{N}{dx}\rfloor\sum\limits^{M/d}_{y=1}\lfloor\frac{M}{dy}\rfloor\]
打个分块,预处理一下后面两项,再前缀和一下\(\mu\) 就可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e4;
int prime[maxn+10];
int vis[maxn+10];
int mu[maxn+10];
int sum[maxn+10];
ll f[maxn+10];
void sieve(){
mu[1]=1;
int p=0;
for(int i=2;i<=maxn;i++){
if(!vis[i]){
vis[i]=1;
prime[++p]=i;
mu[i]=-1;
}
for(int j=1;j<=p&&i*prime[j]<=maxn;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=maxn;i++){
sum[i]=sum[i-1]+mu[i];
}
}
void init(){
for(int i=1;i<=maxn;i++){
ll ans=0;
for(int l=1;l<=i;){
ll r=i/(i/l);
ans+=(ll)(r-l+1)*(ll)(i/l);
l=r+1;
}
f[i]=ans;
}
}
int main(){
memset(vis,0,sizeof(vis));
sieve();
init();
int t,n,m;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
int tmp=min(n,m);
ll res=0;
for(int i=1;i<=tmp;){
int r=min(n/(n/i),m/(m/i));
res+=(ll)(sum[r]-sum[i-1])*(ll)f[n/i]*(ll)f[m/i];
i=r+1;
}
cout<<res<<endl;
}
}
以上是关于P3327 [SDOI2015]约数个数和的主要内容,如果未能解决你的问题,请参考以下文章
洛谷P3327 [SDOI2015]约数个数和 莫比乌斯反演