习题:savrsen(数论,欧拉筛)

如果一个数等于它的所有因数(小于自身的)之和,那么这个数就是完美的。例如,28是完美的,因为28=1+2+4+7+14。

基于这个定义,我们数字n的不完美度定为f(n),它等于n与n的所有因数(小于n的)之和的差的绝对值,因此完美数的不完全度为0,其余自然数的不完全度都大于0。

例如:

●f(6)=|6-(1+2+3)|=0

●f(11)=|11-(1)|=10

●f(24)=|24-(1+2+3+4+6+8+12)|=|-12|=12

写一个程序,对于正整数A和B,计算A和B之间所有数字的不完美度之和:即f(A)+f(A+1)+…+f(B)。

输入格式

第一行输入包含两个整数A和B(1≤A≤B≤1e7)。表示题目中的A和B。

输出格式

输出一个整数。表示f(A)+f(A+1)+…+f(B)。

时间:3000ms

空间:128MB

思路:
数论题,第一反应就是万恶的欧拉,

首先复习欧拉筛

欧拉筛的思路其实跟埃筛的差不多,直接给出代码

void sieve_euler(int n)
{
	/*
	vis是有没有访问过
	prime是因数的储存
	pn是因数个数
	*/
	for(int i=2;i<=n;i++)
	{
		if(vis[i]==0)
			prime[++pn]=i;
		for(int j=1;j<=pn&&i*prime[j]<=n;j++)
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
				break;
		}
	}
}

 

之后是求约数个数

设d[i]为i的约数个数

设num[i]表示将i质因数分解之后最小质因子出现的次数,则d[i]包含了(1+num[i])这个因式

接着,由于i*prime[j]和i都以prime[j]为最小质因子,那么(i*prime[j])一定包含

(1+num[i]+1)这一个因式,且满足num[i*prime[j]]=num[i]+1

于是d[i*prime[j]]=d[i]/(num[i]+1)*(num[i]+2)

喜闻(van)乐见的代码

void sieve_euler_divisor_number(int n)
{
	/*
	d是约数个数
	*/
	d[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(vis[i]==0)
		{
			prime[++pn]=i;
			num[i]=1;
			d[i]=2;
		}
		for(int j=1;j<=pn&&i*prime[j]<=n;j++)
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				num[i*prime[j]]=num[i]+1;
				d[i*prime[j]]=d[i]/(num[i]+1)*(num[i]+2);
				break;
			}
			d[i*prime[j]]=d[i]*2;
			num[i*prime[j]]=1;
		}
	}
}

设psum[i]表示关于i的最小值因子p的等比数列求和式1+p+p^2+...+p^w,

由于i*prime[j]和i均以prime[j]为最小质因子,那么i*prime[j]一定有(psum[i]*p+1)这一因式,

且满足关系psum[i*prime[j]]=psum[i]*p+1

s[i*prime[j]]=s[i]/psum[i]*(psum[i]*p+1)

附上代码辅助理解

void sieve_euler_divisor_sum(int n)
{
	/*
	s是约数和
	*/
	s[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(vis[i]==0)
		{
			prime[++pn]=i;
			psum[i]=s[i]=i+1;
		}
		for(int j=1;j<=pn&&i*prime[j]<=n;j++)
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				psum[i*prime[j]]=psum[i]*prime[j]+1;
				s[i*prime[j]]=s[i]/psum[i]*psum[i*prime[j]];
				break;
			}
			s[i*prime[j]]=s[i]*(prime[j]+1);
			psum[i*prime[j]]=1+prime[j];
		}
	}
}

之后,题目就这么解决了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值