2017.3.19 约数个数和 失败总结

        这个题一眼上去应该不是很难,但除了求约数个数有个分解质因数的技巧之外就不会什么了;;

        本来想着预处理50000以内的约数个数和之后求个前缀和直接乘、、、可见多么蠢、、搞了2h后弃疗了


        结果题解是 要算gcd    (。_。)

           还有莫比乌斯反演、、、 …(⊙_⊙;)…


     好吧,先借机学一下莫比乌斯反演 、、

         其实这道题几乎就是为莫比乌斯而生的(板子题

                


似乎是函数的反函数、、

所以叫反演、、 (*゜ー゜*)

而这个μ函数就是传说中的的莫比乌斯函数;

要注意是F(n/d)

那这个要怎么用?




那此题来说,首先要证明这个式子:


为什么会和gcd有关?

若i和j互质,那么i*j就是对于d(mn)唯一的约数

如果不互质,那么i和j还能再拆出几个数,作为约数

如  i=4 j=6,n=8,j=12;;

i=2*2   j=2*3

那么   i*j=2*2*2*3

可以写出互质的8 * 3

在循环到i=8,j=3时会被算进去、


而这些拆出的数一定可以对答案贡献1

所以用了bool;;

然后原式相当于求1~n、1~m的和:


根据 sigma交换律 和 可以处理处的某个积性函数μ可以得出莫比乌斯反演,:

就是套公式,  【gcd(a,b)==1】= Σ(d|i,d|j)μ(d)             )


注意μ是根据d能否整除i、d能否整除j   对d的一个函数,返回数值

有人可能要问gcd的判断和    i、j、d的整除关系得到的函数有什么关系?

注意多了一个Σ:也就是说它是先用前面四坨Σ枚举了1~n、 1~m所有可能的约数、、而这最后一个Σ则是枚举约数的约数、、(当然,默认N<M)

若d既整除了i,又整除了j,则i和j不互质,它有公因数d、、、

然后就不会了


我们注意到会有很多重复,重复的个数为  下取整(N/i)  所以可以用乘法优化加法,干掉两个Σ、、


这是反演的一步通用优化


再从d(约数)的角度交换一下位置:



对于每个d都要乘每种可能的i、j搭配,但对于n、m只会出现n/d、m/d次,每次搭配又会产生n/(i*d)、 m/(j*d)个重复

   所以都可以乘起来再加


把最右边两项的d写到分子:


我们可以发现有两个不相关的项,可以独立处理:




而且这两个函数计算方式一毛一样,只是定义域值域不一样所以:



就可以化为:


分别处理f函数,再用线筛求出μ函数,就可以做了;;;




码:

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
int mu[50001];
ll f[50001],ans;
 int i,j,n,tot,su[50001],k,t,m;
bool vis[50001];
void eular()
{
	mu[1]=1;	
	for(int i=2;i<=50000;i++)
	{
		if(!vis[i])
		{
		su[++tot]=i;
		mu[i]=-1;//质数统一为 -1 
		}
		for(j=1;i*su[j]<50000&&j<=tot;j++)
		{
	       vis[i*su[j]]=1;
		   if(i%su[j]) 
		   {
		   	mu[i*su[j]]=-mu[i];//合数如果没有>2的次方的质数就看元素个数(取反,即为(-1)^n) 
		   }else 
		   {
		   	mu[i*su[j]]=0;//合数如果是p^n形式,mu就是0 
		   	break;
		   }			
		}			
	}
	 for (i=2; i<=50000; i++) mu[i]+=mu[i-1];  //处理前缀和(因为题目有Σ) 
	for (i=1; i<=50000; i++)  //计算f 
        for (j=1; j<=i; j=k+1){  
            k=i/(i/j);               //可能有点mengbi,k存的是最大的i/j,同 余数之和sum一题 
			f[i]+=(ll)(k-j+1)*(i/j);   //用乘法加速连加
        }  
}
int main()
{     scanf("%d",&t);	eular();
while(t--)
{ 
	scanf("%d%d",&n,&m);
	ans=0;
     for (i=1; i<=m && i<=n; i=j+1){//枚举p,计算贡献  
            j=min(m/(m/i),n/(n/i));  //同余数之和sum的计算方式 
            ans+=f[m/i]*f[n/i]*(mu[j]-mu[i-1]);//用公式+前缀和统计答案  
        }
		  
        if(t)printf("%lld\n",ans);  
        else printf("%lld",ans);
}
}


莫比乌斯反演就是一个渠道,可以通过这个渠道对看似没有办法化简的式子转化为若干子函数,这样复杂度就会降低、

但式子的转化极其灵活,必须确保每一步正确性,

可以说,能用莫比乌斯反演的题都需要极强的数学敏感度和缜密的推理

当然,暴力性价比高、



附一张反演函数计算法则:





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值