如果一个数等于它的所有因数(小于自身的)之和,那么这个数就是完美的。例如,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];
}
}
}
之后,题目就这么解决了。