您的位置:首页 > 其它

poj 1845 Sumdiv

2016-08-19 15:34 429 查看





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 );
}


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

如果有帮助记得支持我一下,谢谢!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: