zoukankan      html  css  js  c++  java
  • poj 1845 Sumdiv (数论)

    题目链接

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

    分析:

    看了小优的博客写的。

     分析来自 http://blog.csdn.net/lyy289065406/article/details/6648539

    (1)   整数的唯一分解定理:

          任意正整数都有且只有一种方式写出其素因子的乘积表达式。

          A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数

    (2)   约数和公式:

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

    (3)   同余模公式:

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

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

     

    有了上面的数学基础,那么本题解法就很简单了:

    1: 对A进行素因子分解

    分解A的方法:

    A首先对第一个素数2不断取模,A%2==0时 ,记录2出现的次数+1,A/=2;

    当A%2!=0时,则A对下一个连续素数3不断取模...

    以此类推,直到A==1为止。

     

    注意特殊判定,当A本身就是素数时,无法分解,它自己就是其本身的素数分解式。

     

    最后得到A = p1^k1 * p2^k2 * p3^k3 *...* pn^kn.
          故 A^B = p1^(k1*B) * p2^(k2*B) *...* pn^(kn*B);


    2:A^B的所有约数之和为:

         sum = [1+p1+p1^2+...+p1^(a1*B)] * [1+p2+p2^2+...+p2^(a2*B)] *...* [1+pn+pn^2+...+pn^(an*B)].


    3: 用递归二分求等比数列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))

    上式红色加粗的前半部分恰好就是原式的一半,那么只需要不断递归二分求和就可以了,后半部分为幂次式,将在下面第4点讲述计算方法。

     

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

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

     

    4:反复平方法计算幂次式p^n

       这是本题关键所在,求n次幂方法的好坏,决定了本题是否TLE。

       以p=2,n=8为例

       常规是通过连乘法求幂,即2^8=2*2*2*2*2*2*2*2

       这样做的要做8次乘法

     

       而反复平方法则不同,

       定义幂sq=1,再检查n是否大于0,

    While,循环过程若发现n为奇数,则把此时的p值乘到sq

    {

       n=8>0 ,把p自乘一次, p=p*p=4     ,n取半 n=4

       n=4>0 ,再把p自乘一次, p=p*p=16   ,n取半 n=2

    n=2>0 ,再把p自乘一次, p=p*p=256  ,n取半 n=1,sq=sq*p

    n=1>0 ,再把p自乘一次, p=p*p=256^2  ,n取半 n=0,弹出循环

    }

    则sq=256就是所求,显然反复平方法只做了3次乘法

    代码:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <cstdio>
     6 #include <vector>
     7 #include <algorithm>
     8 #define LL long long
     9 using namespace std;
    10 const int maxn = 10000+10;
    11 const int mod = 9901;
    12 __int64 power(__int64 p, __int64 n)//反复平方法求(p^n)%mod 
    13 {
    14     __int64 sq = 1;
    15     while(n>0)
    16     {
    17         if(n&1) sq = (sq*p)%mod;
    18         n /= 2;
    19         p = p*p%mod;
    20     }
    21     return sq;
    22 }
    23 __int64 sum(__int64 p, __int64 n)//递归二分求 (1 + p + p^2 + p^3 +...+ p^n)%mod
    24 {
    25     if(n == 0) return 1;
    26     if(n%2)     //奇数二分式 (1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1))
    27     return (sum(p, n/2)*(1+power(p, n/2+1)))%mod;
    28     else       //偶数二分式 (1 + p + p^2 +...+ p^(n/2-1)) * (1+p^(n/2+1)) + p^(n/2)  
    29     return (sum(p, n/2-1)*(1+power(p, n/2+1))+power(p, n/2))%mod;
    30 }
    31 int main()
    32 {
    33     int a, b, p[maxn], n[maxn], ans;
    34     while(cin>>a>>b)
    35     {
    36         int i, k = 0;
    37         for(i = 2; i*i <= a;) //分解整数a,常规情况,根号法+递归法
    38         {
    39             if(a%i == 0)
    40             {
    41                 p[k] = i; n[k] = 0; //p[]代表分解的第k个质数是几,n[]表示第k个质数有多少个
    42                 while(!(a%i))
    43                 {
    44                     n[k]++;
    45                     a /= i;
    46                 }
    47                 k++;
    48             }
    49             if(i==2) i++;
    50             else i += 2; //节省时间
    51         }
    52         if(a!=1) //特殊情况,a为质数。
    53         {
    54             p[k] = a;
    55             n[k++] = 1;
    56         }
    57         ans = 1;
    58         for(i = 0; i < k; i++)
    59         ans = (ans*(sum(p[i], n[i]*b))%mod)%mod; //看分析的公式
    60         cout<<ans<<endl;
    61     }
    62     return 0;
    63 }
  • 相关阅读:
    微信小程序 单选按钮 最佳
    微信小程序 单选按钮的实现
    微信小程序 单选框实现
    Java Code To Create Pyramid and Pattern
    Java language
    npm Err! Unexpected end of JSON input while parsing near
    Node.js Express FrameWork Tutorial
    Higher-Order Function Examples
    Create First HTTP Web Server in Node.js: Complete Tutorial
    Node.js NPM Tutorial: Create, Publish, Extend & Manage
  • 原文地址:https://www.cnblogs.com/bfshm/p/3869206.html
Copyright © 2011-2022 走看看