ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[SDOI2015]约数个数和

2021-04-05 21:34:25  阅读:204  来源: 互联网

标签:约数 lfloor right limits dfrac sum 个数 rfloor SDOI2015


iv.[SDOI2015]约数个数和

完蛋了,我们前几题里面都有\(\gcd(\dots)\),但是这道题没有,怎么办呢?

引理:

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

换句话说,两个数\((i,j)\)积的因数个数,等于\(i\)的所有因数与\(j\)的所有因数中互质的对数。

简单证明(感谢suncongbo巨佬的讲解):

显然各质因数之间相互独立(最后是个数乘在一起,只要每一项都相等,乘积也就相等),我们不如只考虑一个质因数\(p\)。设它在\(i\)中的次数是\(a\),在\(j\)中的次数是\(b\)。那么,在乘积\(i\!j\)中,次数就是\(a+b\)。

考虑仅\(p\)一项为\(i\!j\)贡献了多少因数。显然,是\(a+b+1\)个,次数从\(0\)一直到\(i+j\)。

那么为等式右侧贡献了多少呢?当\(i\)中不取任何\(p\)时,\(j\)中可以取\(1\)到\(b\)个\(p\),共\(b\)种;当\(j\)中不取任何\(p\)时,\(i\)中可以取\(1\)到\(a\)个\(p\),共\(a\)种;除此之外,还有一种\(i\)和\(j\)都不选的,共\(1\)种。综上,为等式右侧它也贡献了\(a+b+1\)。

因为对于每一个单独的\(p\),等式左右的贡献相等;所以综合起来考虑,等式左右贡献的积也相等。

证毕。

然后我们看一看套上这个东西后我们要求什么:

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

这个时候,我们就应该想想有没有可能调换枚举顺序。

优先枚举\(x\)和\(y\),则对于每个\(x\),有\(\dfrac{n}{x}\)个这样的\(i\),满足\(i\leq n\)并且\(x|i\)。对于每个\(y\),则有\(\dfrac{m}{y}\)个这样的\(j\)。

因此有\(ans=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{j}\right\rfloor[\gcd(i,j)==1]\)。

老套路,设\(f(x)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{j}\right\rfloor[\gcd(i,j)==x]\),\(g(x)=\sum\limits_{x|d}f(d)\)。

反演一下,得\(f(x)=\sum\limits_{x|d}g(d)\mu(\dfrac{d}{n})\)。

我们要求的是\(f(1)\),\(f(1)=\sum\limits_{x|1}g(d)\mu(\dfrac{d}{1})=\sum\limits_{x=1}^{\infty}g(d)\mu(d)\)。

我们看一下\(g(d)\)是什么。

有\(g(x)=\sum\limits_{x|d}f(d)=\sum\limits_{x|d}\sum\limits_{i=1}^n\sum\limits_{j=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{j}\right\rfloor[\gcd(i,j)==d]\)

发现这个\(d\)可以是任何\(x\)的倍数。因此有\(g(x)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{j}\right\rfloor[x|\gcd(i,j)]\)

我们将\(x\)除出来,有

\(g(x)=\sum\limits_{i=1}^{\frac{n}{x}}\sum\limits_{j=1}^{\frac{m}{x}}\left\lfloor\dfrac{n}{ix}\right\rfloor\left\lfloor\dfrac{m}{jx}\right\rfloor[1|\gcd(i,j)]=\sum\limits_{i=1}^{\frac{n}{x}}\sum\limits_{j=1}^{\frac{m}{x}}\left\lfloor\dfrac{n}{ix}\right\rfloor\left\lfloor\dfrac{m}{jx}\right\rfloor\)

我们令一个\(sum(x)=\sum\limits_{i=1}^{x}\left\lfloor\dfrac{x}{i}\right\rfloor\),这个东西可以在\(O(n\sqrt{n})\)时间内通过整除分块写出来。

则\(g(x)=sum(\dfrac{n}{x})*sum(\dfrac{m}{x})\)。

又有\(ans=\sum\limits_{x=1}^{\infty}g(d)\mu(d)\),这东西也可以整除分块,因为里面有一个可以整除分块的\(g(d)\)和一个可以求前缀和的\(\mu(d)\)。

然后就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int T,n,m,mu[50100],pri[50100],sum[50100],res;
void getmu(int N){
	mu[1]=1;
	for(int i=2;i<=N;i++){
		if(!pri[i])pri[++pri[0]]=i,mu[i]=-1;
		for(int j=1;j<=pri[0]&&i*pri[j]<=N;j++){
			pri[i*pri[j]]=true;
			if(!(i%pri[j]))break;
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N;i++)mu[i]+=mu[i-1];
}
void getsum(int N){
	for(int i=1;i<=N;i++)for(int l=1,r;l<=i;l=r+1)r=i/(i/l),sum[i]+=(r-l+1)*(i/l);
}
signed main(){
	scanf("%lld",&T),getmu(50000),getsum(50000);
	while(T--){
		scanf("%lld%lld",&n,&m);
		if(n>m)swap(n,m);
		res=0;
		for(int l=1,r;l<=n;l=r+1)r=min(n/(n/l),m/(m/l)),res+=(mu[r]-mu[l-1])*sum[n/l]*sum[m/l];
		printf("%lld\n",res);
	}
	return 0;
}

标签:约数,lfloor,right,limits,dfrac,sum,个数,rfloor,SDOI2015
来源: https://www.cnblogs.com/Troverld/p/14619520.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有