约数的和及约数的个数
1.约数的个数等于:所有质因数的指数加上1后的乘积;
若一个数分解质因数后为(am)*(bn),其中a,b均为质因数;m,n均为相应质因数的指数.
则约数个数为(m+1)(n+1).
例如: (1)12=2²3,质因数有2和3,其指数分别为2和1,那么12的约数有(2+1)(1+1)=6(个);
(2)60=2²35,质因数2,3,5的指数分别为2,1,1,那么60的约数有(2+1)(1+1)(1+1)=12(个).
2.一个数所有约数之和等于:先把每个质因数从0次幂一直加到其最高次幂,再把每个相应质因数幂的和相乘.
若一个数分解为(am)*(bn),则这个数所有约数的和为: (a0+a1+a2+a3+…+am)*(b0+b1+b2+b3+…+bn).
例如:(1)12=2²3,则12所有约数的和为:(20+21+22)*(30+3^1)=74=28;
(2)60=2²35=(20+21+22)*(30+31)*(50+5^1)=746=168.
[ AHOI2005]约数研究 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) (求1-n约数的个数的和)
CF1512G Short Task - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)(欧拉筛求约数和)
法一:求1-n任意数约数和 O(n*logn)
#define ll long long
int s[1000010];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int i,t;
memset(s,0,sizeof(s));
for(i=1;i<=n;i++)
for(t=i;t<=n;t+=i)
s[t]++; // 求约数的个数
}
}
//求约数的和
for(i=1;i<=n;i++)
for(t=i;t<=n;t+=i)
s[t]+=i;
//s[i]为i的约数和
法二 欧拉筛求约数和 O(n)
// s=an*bm*ct*....
// res=(a0+a1+...an)*(b0+b1+...bm)*(c0+c1+...ct)*...
void get_fc(){
res[1]=fc[1]=1;
for(int i=2;i<maxn;i++)
res[i]=-1;
for(int i=2;i<maxn;i++){
if(!vis[i]){
pr[++cnt]=i; // 质数
fc[i]=i+1;
}
for(int j=1;j<=cnt&&i*pr[j]<maxn;j++)
{
vis[i*pr[j]]=1;
if(i%pr[j]==0){
fc[i*pr[j]]=fc[i]+(fc[i]-fc[i/pr[j]])*pr[j]; // 合数
break;
}
fc[i*pr[j]]=fc[i]+fc[i]*pr[j];
}
}
}
get_fc();
for(int i=2;i<maxn;i++){
if(fc[i]>=maxn)
continue;
if(res[fc[i]]==-1)
res[fc[i]]=i;
}
//res[i] 为任意数的约数和
//法一:(o(n)算法) //求1到n的约数和的和
// ∑(1->n)f(i) = sum = ∑ ⌊n/i⌋∗i //约数和公式
for(i=1;i<=n;i++) sum+=(n/i)*i;
//法二(延伸自法一) // 求1到n的约数和的和 <O(n)
以12为例,列出来是12,6,4,3,2,2,1,1,1,1,1,1
发现这里面有些数是重复的,考虑能不能把这些重复的一次算出来
把那些相同的值用区间来表示,那只要求出左右端点l,r来就好了
l比较好求,观察上面的数列,l 就是上一个r加1,初始l=1
那 r怎么求呢?其实很简单
r=n/(n/l)
l是那个数列的下标,所以(n/l)就是约数,那 r 就显然了,如果不知道为什么,那就再看一遍“1−n中有几个数是 d 的倍数”。
ll sum(int n) {
if(n<=1) return n;
ll ans=0;
for(ll l=1,r;l<=n;l=r+1) {
r=n/(n/l);
ans+=(n/l)*(l+r)*(r-l+1)/2;
}
return ans;
}