POJ 1845 Sumdiv(约数和公式+等比数列求和)

本文介绍了一种计算已知整数所有因子之和的方法,使用了数学中的约数和公式,并通过C++代码实现了一个高效的算法来解决该问题。算法中考虑了取模操作可能导致的问题,并采用二分法计算等比数列的和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

约数和公式

对于已经分解的整数A=(p1^k1)(p2^k2)(p3^k3)….(pn^kn)
有A的所有因子之和为
S = (1+p1+p1^2+p1^3+…p1^k1) * (1+p2+p2^2+p2^3+….p2^k2) * (1+p3+ p3^3+…+ p3^k3) * …. * (1+pn+pn^2+pn^3+…pn^kn)

代码

由于取模数只有9901,如果素因子刚好是9901*x+1,那么就无法求出逆元,因此用二分求等比数列的和

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <cmath>
#include <algorithm>
#include <queue>

#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
const int INF=0x3f3f3f3f;
const int maxn=1e4+50;
const int mod=9901;
#define pii pair<int,int>
#define mp(a,b) make_pair(a,b)
typedef long long ll;
typedef unsigned int ui;
using namespace std;

bool notPrime[maxn];
int prime[maxn];
int cnt;
void initPrime(){
    mem(notPrime,0);
    cnt=0;
    for(int i=2;i<maxn;i++){
        if(notPrime[i]) continue;
        prime[cnt++]=i;
        for(int j=2*i;j<maxn;j+=i)
            notPrime[j]=true;
    }
    notPrime[0]=notPrime[1]=1;
}

map<ll,ll> ma;
map<ll,ll>::iterator it;
void getFac(int n){
    for(int i=0;i<cnt;i++){
        int p=prime[i];
        if(p>n) break;
        while(n%p==0){
            ma[p]++;
            n/=p;
        }
    }
    if(n!=1) ma[n]++;
}

ll qPow(ll x,ll n){
    ll ret=1;
    while(n){
        if(n&1) ret=ret*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return ret;
}

ll sum(ll p,ll n){//计算1+p+p^2+````+p^n
    if(p==0)return 0;
    if(n==0)return 1;
    if(n&1){
        return ((1+qPow(p,n/2+1))%mod*sum(p,n/2)%mod)%mod;
    }
    else return ((1+qPow(p,n/2+1))%mod*sum(p,n/2-1)+qPow(p,n/2)%mod)%mod;

}

int main()
{
#ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
    //freopen("d:\\out.txt","w",stdout);
#endif
    initPrime();
    int a,b;
    while(~scanf("%d %d",&a,&b)){
        ma.clear();
        if(a==0){
            puts("1");
            continue;
        }
        getFac(a);
        ll ans=1;
        for(it=ma.begin();it!=ma.end();it++){
            it->second*=b;
            //cout<<it->first<<" "<<it->second<<endl;
            ll q=it->first,mi=it->second;
            ans=(ans*sum(q,mi))%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值