poj 1845 Sumdiv



Sumdiv
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 19177 Accepted: 4819

Description

Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).

Input

The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.

Output

The only line of the output will contain S modulo 9901.

Sample Input

2 3

Sample Output

15

Hint

2^3 = 8. 
The natural divisors of 8 are: 1,2,4,8. Their sum is 15. 
15 modulo 9901 is 15 (that should be output). 

Source

题意:

:求 A^B的所有约数之和对9901取模后的结果.

以下知识要掌握:

1. 计算约数之和公式


设一个数为A,分解质因数得
A=a1^b1 * a2^b2 * a3^b3 an^bn [a1 a2 a3 .表示不同的质因数 b1 b2 b3 表示每个质因数的次方数(即相同质因数的个数)]
则有:
A的约数的个数=(1+b1)(1+b2)(1+b3).(1+bn)
A的约数的总和=(1+a1+a1^2+a1^3+a1^4+.a1^b1)*(1+a2+a2^2+a2^3+a2^4+.a2^b2).(1+an+an^2+an^3+an^4+.an^bn)
举例说明白:
180=2^2*3^2*5(
这个式子能够由唯一分解定理得出,就是学习知识点2
个数=(1+2)(1+2)(1+1)=18
总和=(1+2+4)(1+3+9)(1+5)=546(
这一题最终所要求取的模,如何求取就要学习知识点3了


2. 唯一分解定理


算术基本定理,又称为正整数的唯一分解定理,即:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。例如:                          

算术基本定理的内容由两部分构成:
分解的存在性;

分解的唯一性,即若不考虑排列的顺序,正整数分解为素数乘积的方式是唯一的。

那如何实现唯一分解定理呢?在代码中你会得到答案的。


3. 等比数列1+pi+pi^2+pi^3+...+pi^n可以由二分求得(即将需要求解的因式分成部分来求解)

那约数总和如何求取?

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

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


4. 同余模公式


(a+b)%m=(a%m+b%m)%m

(a*b)%m=(a%m*b%m)%m


5. 蒙哥马利模乘


对幂次方取模的优化


蒙哥马利模乘的优点在于减少了取模的次数(在大数的条件下)以及简化了除法的复杂度(在2的k次幂的进制下除法仅需要进行左移操作)。模幂运算是RSA 的核心算法,最直接地决定了RSA 算法的性能。针对快速模幂运算这一课题,西方现代数学家提出了大量的解决方案,通常都是先将幂模运算转化为乘模运算。

例如求D=C^15%N
由于:a*b % n = (a % n)*(b % n) % n
所以令:
C1 =C*C % N =C^2 % N
C2 =C1*C1 % N =C^3 % N
C3 =C2*C2 % N =C^6 % N
C4 =C3*C3 % N =C^7 % N
C5 =C4*C4 % N =C^14 % N
C6 =C5*C % N =C^15 % N
即:对于E=15的幂模运算可分解为6 个乘 模运算
经过以上知识的补充就可以知道怎样做此题了,希望对读者能够有更好的帮助。


代码如下:


Memory: 388K		Time: 0MS
Language: G++		Result: Accepted
Source Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int MAX = 9901;
int n, m;
int size;
struct node
{
    int prime;   //存数
    int num;     //存幂
}Pri[10002];

/*唯一分解定理的实现*/
void PrimeNum()
{
    int i;
    size = 0;
    for ( i = 2;i*i <= n; i++ )
    {
        if ( n%i == 0 )
        {
            Pri[size].prime = i;
            Pri[size].num = 0;
            while (n%i == 0)
            {
                n = n/i;
                Pri[size].num++;
            }
            size++;
        }
        if ( i != 2 )
        {
            i++;
        }
    }
    if ( n != 1 )
    {
        Pri[size].prime = n;
        Pri[size].num = 1;
        size++;
    }
}

/*蒙哥马利模乘法*/
int power( long long pe, long long pi )
{
    int exponen = 1;
    while (  pi >= 1 )
    {
        if ( pi%2 == 1 )
        {
            exponen = (exponen*(pe%MAX))%MAX;
        }
        pi = pi/2;
        pe = pe*pe%MAX;
    }
    return exponen;
}

/*等比公式的二分法*/
int Geomet( long long pe, long long pi )
{
    if ( pi == 0 )
        return 1;
    if ( pi%2 == 0 )
    {
        return( (Geomet(pe, pi/2-1)%MAX)* ((power(pe, pi/2+1)+1)%MAX) +power(pe, pi/2) )%MAX;
    }
    else
    {
        return (Geomet(pe, pi/2)%MAX)*((power(pe, pi/2+1)+1)%MAX)%MAX;
    }
}

int main()
{
    int i;
    scanf ( "%d %d", &n, &m );

    PrimeNum();

    int sum = 1;

    /*计算约数之和公式*/
    for ( i = 0;i < size; i++ )
    {
        /* 同余模公式*/
        sum = (sum* ( Geomet (Pri[i].prime, Pri[i].num*m) %MAX ) %MAX);
    }

    printf ( "%d\n", sum );
}

代码菜鸟,如有错误,请多包涵!!!

如果有帮助记得支持我一下,谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值