poj1845 Sumdiv

poj1845 Sumdiv 数学题

令人痛苦van分的数学题!

 

题意:求a^b的所有约数(包括1和它本身)之和%9901

这怎么做呀!!!

百度:约数和定理,会发现 p1^a1 * p2^a2 * ... * pn^an
这个数的约数和是:
(1 + p1 + p1^2 + ... + p1^a1) * (1 + p2 + ... + p2^a2) * ... * (1 + pn + ... + pn^an)

证明:由乘法原理可直接证明

然后我们对于a^b运用这个公式即可。
那么对于 (1 + pi + ... + pi^ai) 我们难道要暴力求吗?
不,这显然是个等比数列!我们用公式!

那么我们就成功WA了!

…查找原因,发现q-1可能是9901的整数倍,导致无法求逆元。
那么我们退而求次,用递归求和!

a1 + a1*q + a1*q^2 + ... + a1*q^n = (q^(n/2) + 1) * (a1 + a1*q + ... + a1*q^(n/2))

把上面那个式子分n的奇偶讨论一下就行了。

(法②:当q-1为9901的整数倍时,q % 9901 = 1,又因为a1 = 1,上式显然为n + 1)

然后我们开开心心的调了一年之后WA了….
查找原因:没开long long导致qpow爆了
然后就A了!

 1 //poj1845 sumdiv
 2 #include <cstdio>
 3 using namespace std;
 4 const int N = 50000,mo = 9901;
 5 int p[N][2],P;
 6 int qpow(int a,int b) {
 7     int ans=1;
 8     while(b) {
 9         if(b&1) {
10             ans=ans*a%mo;
11         }
12         a=a*a%mo;
13         b=b>>1;
14     }
15     return ans;
16 }
17 
18 void split(int a,int b) {
19     for(int i=2; a>1; i++) {
20         if(!(a%i)) {
21             p[++P][0] = i;
22         }
23         while(!(a%i)) {
24             a/=i;
25             p[P][1]++;
26         }
27     }
28     for(int i=1; i<=P; i++) {
29         p[i][1]*=b;
30     }
31     return;
32 }
33 
34 long long getQsum(int a1,int q,int n) {
35     if(q==1) {
36         return a1*n%mo;
37     }
38     if(n==1) {
39         return a1;
40     }
41     if(n&1) { //奇数
42         long long ans = ((1+qpow(q,n>>1))*getQsum(a1,q,n>>1)+(a1*qpow(q,n-1)))%mo;
43         return ans;
44     }
45     //偶数
46     long long ans = ((1+qpow(q,n>>1))*(getQsum(a1,q,n>>1)))%mo;
47     return ans;
48 }
49 
50 void solve() {
51     long long ans=1;
52     for(int i=1; i<=P; i++) {
53         int temp=getQsum(1,p[i][0],p[i][1]+1);
54         ans*=temp;
55         ans%=mo;
56     }
57     printf("%I64d",ans);
58     return;
59 }
60 
61 int main() {
62     //freopen("in.in","r",stdin);
63     //freopen("my.out","w",stdout);
64     int a,b;
65     scanf("%d%d",&a,&b);
66     if(!a) {
67         printf("0");
68         return 0;
69     }
70     split(a,b);
71     solve();
72     return 0;
73 }
AC代码:

我们学到了什么?

我们学到了什么?

  1. 约数和定理
  2. How to 求逆元
  3. How to 递归求等比数列和
  4. 开long long!!!!

————————end————————

 

posted @ 2018-05-05 17:18  garage  阅读(120)  评论(0编辑  收藏  举报