poj 1845 Sumdiv(分治递归,数论,快速幂)

Sumdiv

题意:对A的B次方的所有约数之和mod 9901

思路:对A分解质因数 A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数;

           所以 A^B = p1^(k1*B) * p2^(k2*B) *...* pn^(kn*B);根据乘法分配律,A^B的所有约数之和为 [1+p1+p1^2+...+p1^(a1*B)] * [1+p2+p2^2+...+p2^(a2*B)] *...*[1+pn+pn^2+...+pn^(an*B)].

    考虑到等比数列求和,但是因为要取模而且等比数列求和有除法,所以换一种思路,用分治法进行等比数列求和

1)若n为奇数,一共有偶数项,则:
      1 + p + p^2 + p^3 +...+ p^n
      = (1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1))

n为偶数则类似。

#include <cstdio>
#include <iostream>
#include <math.h>

using namespace std;
typedef long long ll;
ll mod = 9901;
ll a, b;
ll power(ll a, ll b)
{
    ll ans = 1;
    for(; b; b >>= 1)
    {
        if(b & 1)ans = ans * a % mod;
        a = a * a % mod;
    }
    return ans;
}
ll sum(ll p, ll c)
{
    if(c == 0) return 1;
    if(c % 2 == 1) return  (1 + power(p, (c + 1) / 2)) * sum(p, (c - 1) / 2) % mod;
    return ((1 + power(p, c / 2)) * sum(p, c / 2 - 1) + power(p, c)) % mod;
}
int main()
{
//    freopen("in.txt", "r", stdin);
    cin >> a >> b;
    ll pn[10000];
    ll pk[10000];
    ll len = sqrt(a * 1.0);
    ll cnt = 0;
    for(int i = 2; i <= len; i++)
    {
        if(a % i == 0)
        {
            pn[cnt] = i;
            pk[cnt] = 0;
            while(a % i == 0)
            {
                a /= i;
                pk[cnt]++;
            }
            cnt++;
        }
    }

    if(a != 1)
    {
        pn[cnt] = a;
        pk[cnt] = 1;
        cnt++;
    }
    for(int i = 0; i < cnt; i++)
    {
        pk[i] *= b;
    }
    ll ans = 1;
    for(int i = 0; i < cnt; i++)
    {
        ans = ans * sum(pn[i], pk[i]) % mod;
    }
    cout << ans << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值