Sumdiv

Posted happy_code

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sumdiv相关的知识,希望对你有一定的参考价值。

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 20971   Accepted: 5290

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). 
 
//题意:给出 A,B 问 A^B 的所有因数(包括 1 和本身)之和余 9901 的值
这道题用了很多个数学的方法,一个个讲
首先,我们要知道怎么分解一个数,所以用到了<唯一分解定理>: 任何大于1的自然数,都可以唯一分解成有限个质数的乘积
将 A 分解后,将所有质数个数乘 B 就是 A^B 的该质数的个数了.
代码:
 1 void Zhi()
 2 {
 3     int t = a;
 4     for (int i=2;i*i<=a;i++)
 5     {
 6         if (t%i==0)
 7         {
 8             p[z]=i;
 9             p_n[z]=1;
10             t/=i;
11             while (t%i==0)
12             {
13                 p_n[z]++;
14                 t/=i;
15             }
16             z++;
17         }
18         if (t==1) break;
19         if (i!=2)
20             i++;//2.3.5.7.9...
21     }
22     if (t!=1)//本身就是质数
23     {
24         p[z]=t;
25         p_n[z]=1;
26         z++;
27     }
28 }
View Code
 
为什么要分解呢,因为要求约数和
<约数和公式>

对于已经分解的整数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)

但是,使用这个公式不能用等比求和公式,因为我们要求余,等比数列求和公式求余就错了

所以用到了二分求等比数列和

 用递归二分求等比数列1+pi+pi^2+pi^3+...+pi^n:

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

      = (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2) * (1+p^(n/2+1))
      = (1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1))

   上式中加粗的前半部分恰好就是原式的一半,那么只需要不断递归二分求和就可以了,后半部分为幂次式,在后面就说快速幂。

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

      = (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2-1) * (1+p^(n/2+1)) + p^(n/2)
      = (1 + p + p^2 +...+ p^(n/2-1)) * (1+p^(n/2+1)) + p^(n/2);

   上式加粗的前半部分恰好就是原式的一半,依然递归求解

前提是要用到<同余模公式>

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

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

还有<快速幂>

应该不难,看看代码能懂

 1 int Mi(int a, int b)//快速幂
 2 {
 3     int res = 1;
 4     a %= MOD;
 5     while (b)
 6     {
 7         if (b%2==1)
 8             res = (res * a)%MOD;
 9         a = (a * a)%MOD;
10         b /= 2;
11     }
12     return res;
13 }
View Code

好了,递归二分代码

1 int Erfen(int p , int n)//求 1 + p + p^2 + p^3+ ... +p^n
2 {
3     if (n==0) return 1;
4     if (n%2==1)
5         return ((Mi(p,n/2+1)+1)  * Erfen(p,n/2))%MOD;
6     else
7         return ((1+Mi(p,n/2+1)) * Erfen(p,n/2-1) + Mi(p,n/2))%MOD;
8 }
View Code

 

上总代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 
 5 using namespace std;
 6 
 7 #define MOD 9901
 8 
 9 int a,b,z;
10 int p[10000];   //质数
11 int p_n[10000];//质数个数
12 
13 void Zhi()
14 {
15     int t = a;
16     for (int i=2;i*i<=a;i++)
17     {
18         if (t%i==0)
19         {
20             p[z]=i;
21             p_n[z]=1;
22             t/=i;
23             while (t%i==0)
24             {
25                 p_n[z]++;
26                 t/=i;
27             }
28             z++;
29         }
30         if (t==1) break;
31         if (i!=2)
32             i++;//2.3.5.7.9...
33     }
34     if (t!=1)//本身就是质数
35     {
36         p[z]=t;
37         p_n[z]=1;
38         z++;
39     }
40 }
41 
42 int Mi(int a, int b)//快速幂
43 {
44     int res = 1;
45     a %= MOD;
46     while (b)
47     {
48         if (b%2==1)
49             res = (res * a)%MOD;
50         a = (a * a)%MOD;
51         b /= 2;
52     }
53     return res;
54 }
55 
56 int Erfen(int p , int n)//求 1 + p + p^2 + p^3+ ... +p^n
57 {
58     if (n==0) return 1;
59     if (n%2==1)
60         return ((Mi(p,n/2+1)+1)  * Erfen(p,n/2))%MOD;
61     else
62         return ((1+Mi(p,n/2+1)) * Erfen(p,n/2-1) + Mi(p,n/2))%MOD;
63 }
64 
65 int main()
66 {
67     while (scanf("%d%d",&a,&b)!=EOF)
68     {
69         z=0;//质数个数
70         Zhi();
71 
72         int ans = 1;
73         for (int i=0;i<z;i++)
74         {
75             ans = (ans * Erfen(p[i],p_n[i]*b))%MOD;
76         }
77         printf("%d\\n",ans);
78     }
79     return 0;
80 }
View Code

 

 

 

以上是关于Sumdiv的主要内容,如果未能解决你的问题,请参考以下文章

Sumdiv 二分

Sumdiv 二分

Sumdiv

Sumdiv POJ - 1845

poj1845 Sumdiv

poj_1845_Sumdiv