因子个数及因子之和问题

 在数论中有一个质因数分解定理,可利用其中的一些性质来求一个数的因子个数及其因子和,下面附上定理及代码。

 下面是代码

#include<bits/stdc++.h>
using namespace std;
//求因子个数 
int fun1(int x)
{
    int len=sqrt(x);
    int ans=1;
    int cnt;
    for(int i=2;i<=len;i++)
    {
        cnt=0;
        while(x%i==0)
        {
            x/=i;cnt++;
        }
        ans*=(1+cnt);
    }
    if(x>1) ans*=2;//x>1说明还剩最后一个因子,所以要乘(1+1)
    return ans;
}
//求因子和 
int fun2(int x)
{
    int len=sqrt(x);
    int ans=1;
    int cnt;
    for(int i=2;i<=len;i++)
    {
        cnt=1;
        while(x%i==0)
        {
            cnt*=i;
            x/=i;
        }
        ans*=(cnt*i-1)/(i-1);
    }
    if(x>1) ans*=(x+1);同理剩下一个因子,且其指数为1,所以乘以(x^2-1)/(x-1)=(x+1)
    return ans;
}
int main()
{
    int n;
    cin>>n;
    printf("%d %d",fun1(n),fun2(n));
    return 0; 
}

下面给出一道相关例题:

Sumdiv

题意:

有两个自然数a和b(a,b≤50000000)

求a的b次方的所有约数之和模9901

输入格式:一行,包含由空格分隔的两个自然数a和b

输出格式:一行,a的b次方的约数和模9901

样例

输入: 2 3

输出:15

分析:容易想到我们需要先对a进行质因数分解,再对a的各个质因数的幂次乘以b即得a^b的质因数分解式,数据太大,所以我们必须要取模,我们容易发现等比数列求和公式中有分母,但是再模运算中不允许有除法的出现,所以我们必须求出分母相对于模值的逆元,用乘以逆元的方式来代替除法操作,但需注意的是,a关于b有逆元的充分条件是(a,b)=1,所以当分母与模值不互质时需要特殊处理一下,但我们需要注意到的是模值是一个质数,故当且仅当分母是模值的倍数时才不能求得相对应的乘法逆元,求逆元我们常用的操作是费马小定理即(a^(p-1),p)=1,条件是(a,p)=1,则a对应模值为p的逆元为a^(p-2),所以逆元我们可以用快速幂求得,下面是这道题的代码

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=9901;
const int N=50003;
ll fact[N];
ll flag;
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1) ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
void init(ll a,ll b)//质因数分解
{
	ll l=sqrt(a);
	for(int i=2;i<=l;i++)
		while(a%i==0)
		{
			fact[i]+=b;
			a/=i;
		}
	if(a!=1) flag=a;
}
ll fun(ll a,ll b)//求出a^0+a^1+……+a^b
{
	if((a-1)%mod==0) return (b+1);//特判不互质的情况
	ll ans=(qpow(a,b+1)+mod-1)%mod;
	ll infact=qpow(a-1,mod-2);//求逆元
	return (ans*infact%mod);
}
int main()
{
	ll a,b;
	flag=0;
	cin>>a>>b;
	init(a,b);
	ll ans=1;
	int temp=sqrt(a);
	for(int i=2;i<=temp;i++)
		if(fact[i]) ans=ans*fun(i,fact[i])%mod;
	if(flag) ans=ans*fun(flag,b)%mod;
	printf("%lld",ans);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值