zoukankan      html  css  js  c++  java
  • poj1845(快速幂+唯一分解定理+求约数和公式+等比数列)

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    const int mod=9901;
    const int maxn=10000;
    int p[maxn];
    int k[maxn];
    
    long long power(long long p,long long n){
        long long ans=1%p;
        for (;n;n>>=1){
            if(n&1) ans=(long long)p*ans%mod;
            p=p*p%mod;
        }
        return ans;
    }
    
    long long sum(long long p,long long n){
              if(n==0)  return 1;
              if(n%2) return (sum(p,n/2)*(1+power(p,n/2+1)))%mod;
              else return (sum(p,n/2-1)*(1+power(p,n/2+1))+power(p,n/2))%mod;
    }
    
    int main(){
        int a,b;
        scanf("%d%d",&a,&b);
        int n=0;
        int i;
        for (i=2;i*i<=a;){
              if(a%i==0){
                    p[n]=i;
                while(a%i==0){
                    k[n]++;
                    a/=i;
                }
                n++;
            }
            if (i==2) i=3;
            else i+=2;
        }
        if(a!=1){
            p[n]=a;
            k[n++]=1;
        }
        int ans=1;
        for (int i=0;i<n;i++){
            ans=(ans*sum(p[i],k[i]*b)%mod)%mod;
        }
        printf("%d
    ",ans);
    return 0;
    }

    转载请注明出处:優YoU  http://user.qzone.qq.com/289065406/blog/1309237394

    大致题意:

    求A^B的所有约数(即因子)之和,并对其取模 9901再输出。

     

    解题思路:

    要求有较强 数学思维 的题

    应用定理主要有三个:

    要求有较强 数学思维 的题

    应用定理主要有三个:

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


    2A^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次乘法 

  • 相关阅读:
    LeetCode偶尔一题 —— 617. 合并二叉树
    《剑指offer》 —— 链表中倒数第k个节点
    《剑指offer》 —— 青蛙跳台阶问题
    《剑指offer》—— 二维数组中的查找
    《剑指offer》—— 替换空格
    《剑指offer》—— 合并两个排序的链表
    《剑指offer》—— 礼物的最大价值
    生成Nuget 源代码包来重用你的Asp.net MVC代码
    Pro ASP.Net Core MVC 6th 第四章
    Pro ASP.NET Core MVC 6th 第三章
  • 原文地址:https://www.cnblogs.com/lmjer/p/8857877.html
Copyright © 2011-2022 走看看