zoukankan      html  css  js  c++  java
  • POJ1845-Sumdiv大数约数和

    题目链接:http://poj.org/problem?id=1845

    题目大意:

      求A^B的所有约数和s。A和B都很大(0<=A,B<=50000000).

    题目分析:

      这道题让我学会了很多东西,很多我之前没有见识过的专属于数学的技巧之类的。看了别人的博客,受益匪浅。现总结如下:

      先来分析一下这道题目,再来讲技巧吧。

      这道题真是大数中的大数。刚看到这道题就完全没有头脑。全凭小优的指点(http://blog.csdn.net/lyy289065406) 。

      (1) 整数唯一分解定理 

      任何整数都可以且尽可以分解成若干个素数相乘的形式,如下:

      A=p1^k1 * p2^k2 *……* pn^kn;其中的pi各表示一个素数.

      (2)约数和公式

      按照整数的分解定理,我们有一个整数的约数之和公式为:

      S=(1+p1+p1^2+……p1^k1) * (1+p2+p2^2+……+p2^k2)  *……*  (1+pn+pn^2+……+pn^kn).

      (3) 同余模公式

                (a+b)%mod=(a%mod + b%mod)%mod;

         (a*b)%mod=(a%mod * b%mod)%mod;

      *以上的三个数学知识是解这道题的关键。请先消化理解以后再往下面看*

      第二部份呢,我们来利用上面的理论基础分析一下这道题。

      如果有:A=p1^k1 * p2^k2 *……* pn^kn;

      那么有:A^B=p1^(k1*B) * p2^(k2*B) *……* pn^(kn*B);

      因而   : S=[1+p1+p1^2+……p1^(k1*B)]  *  [1+p2+p2^2+……+p2^(k2*B)]  *……*  [1+pn+pn^2+……+pn^(kn*B)].

      至此,答案已经很明了了,下面的事情就是如何来用程序实现上面的过程了,注意,最终的S是要mod 9901 的哦!

      *还有什么不明白的吗?可以在讨论区提问哦*

      第三部份,我们来尝试用程序实现上述公式:

      (1)质因数分解

      在这里我用的根号法+递归法(名字是小优那里借鉴的),起初还没想明白这个方法,试图用素数表的方式来解决问题,看到五千万那么大就没有敲了,如果感兴趣,可以自己试一试哦。看一看下面的“根号法+递归法”吧。

    for(int i=2;i*I<=A;) //根号法的体现
    {
        int k=0;//这是p[ ]和n[ ]的指针。p是存素因子的,n是存其指数
        if (A%i==0)
        {
            p[k]=i;
            n[k]=0;
            while(A%i) //这是递归法的体现,找到一个素因子就用此法计算其个数
            {
                n[k]++;
                A/=i;
            }
            k++;
        }
        if(i==2) //这是所谓的奇偶法,除了2其余素数都是奇数哦
             i++;
        else
            i+=2;
    }
    
    if(A!=1)//常规来讲,这时候的A已经被分解剩下1了,除非A本身就是素数
    {
        p[k]=A;
        n[k++]=1;
    }

      乍看上去,这也太慢了吧,怎么一个个去试,会不会出现重复啊?会不会把非质数当成是质因子啊?这个问题呢就留给大家自己思考啊。*

      

      (2)二分法求等比数列的和

      解决了A的分解问题,自然需要来解决一下S的求解问题,很明显S是一系列以pi为公比的等比数列和 之积。只要能解决等比数列和的问题那这道题就迎刃而解了啊。最最直接的方法是利用求和公式,但是别忘了,我们的S可是还需要对9901取模的,[pi^(ki*B)-1]/(pi-1)这个结果中pi-1未必和9901互素!因而,解决这个问题,就只好用二分法:

       对于一个等比数列求和  S=1+q+q^2+……q^n

       如果n为奇数,那么一共就有偶数个项了,

         S=[1+q+……+q^(n/2)] * [1+q^(n/2+1)]

       如果n为偶数,那么一共就是有奇数个项了,

       S=[1+q+……+q^(n/2-1] * [1+q^(n/2+1)]+q^(n/2)

      *如果记不住上面的公式的话,就举个例子自己算算,结果自然就很清楚了。*

      现在所有的理论问题都解决了,就看代码吧。

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 #define size 10000
     5 #define mod 9901
     6 
     7 int p[size],n[size];
     8 
     9 long long pow3(long long int a,long long int b )//快速幂
    10 {
    11     long long int r = 1, base = a;
    12     while( b != 0 )
    13     {
    14         if( b & 1 )
    15             r =(r * base) % mod;
    16         base =(base * base) % mod;
    17         b >>= 1;
    18     }
    19     return r;
    20 }
    21 
    22 long long sum(long long p,long long n)//二分递归求解等比数列之和
    23 {
    24     if(n==0)
    25         return 1;
    26     if(n%2)
    27         return ((sum(p,n/2) % mod) * (1+pow3(p,n/2+1))% mod )% mod;
    28     else
    29         return (((sum(p,n/2-1) % mod) * (1+pow3(p,n/2+1))% mod ) % mod + pow3(p,n/2) %mod)%mod;
    30 }
    31 
    32 int main()
    33 {
    34     int A,B;
    35     while(scanf("%d%d",&A,&B)!=EOF)
    36     {
    37         int js=0;
    38         for(int i=2;i*i<=A;)//质因数分解A,根号法和递归法
    39         {
    40             if(A%i==0)
    41             {
    42                 p[js]=i;
    43                 n[js]=0;
    44                 while(A%i==0)
    45                 {
    46                     n[js]++;
    47                     A/=i;
    48                 }
    49                 js++;
    50             }
    51             if(i==2)
    52                 i++;
    53             else
    54                 i+=2;
    55         }
    56         if(A!=1)//A本身就是素数的
    57         {
    58             p[js]=A;
    59             n[js++]=1;
    60         }
    61 
    62         long long ans=1;
    63         for(int i=0;i<js;i++)
    64         {
    65             ans=( ans * sum(p[i],n[i]*B)%mod )%mod;
    66         }
    67         cout<<ans<<endl;
    68     }
    69     return 0;
    70 }
    POJ1845
  • 相关阅读:
    python day 09 文件操作
    day python calss08 深浅copy
    python.day05
    pytonn04day
    python开发day03
    python开发day02
    python 变量名的规范
    设备描述表
    GDI基础
    windows编程-窗口
  • 原文地址:https://www.cnblogs.com/xiaozhuyang/p/POJ1845-Sumdiv.html
Copyright © 2011-2022 走看看