zoukankan      html  css  js  c++  java
  • POJ 1845 (洛谷 :题目待添加)Sumdiv

    约数和

    题目描述

    给出a和b求a^b的约数和

    输入格式:

    一行两个数a,b。

    输出格式:

    一个数表示结果对 9901 的模。

    Input

    2 3

    Output

    15

    SB的思路:

    这是一道典型的数论题,本蒟蒻在做的时候首先瞄出a为质数的解法(简直废话,是个人都看得出),

     即sum(a,b)=a^0+a^2+a^3+···+a^(b-1)+a^b,然后自以为搞出了什么,结果随手举个反例就Wa了,但是很明显也很容易想到要用快速幂。

    然后我又想到洛谷月赛T1,以及一道要用到费马小定理的题目,加上我打出的表,我发现:

              a=(a1^k1)*(a2^k2)*···*(an^kn)   (其中a1为质因子,k1为该质因子个数

      那么a^b=(a1^k1)^b*(a2^k2)^b*···*(an^kn)^b

      再加上质数的约数和的规律我的表

      a^b的约数和(暂且用sum表示)就是sum(a,b)=sum(a1,k1*b)*sum(a2,k2*b)*···*sum(an,kn*b)

      然后我很愚蠢地使用只快速幂来求约数和,这个想法太愚蠢了我都没脸说(我当时是这样想的:a^b的约数和做两次快速幂就出来了,即在做a^b和a^(b-1)的过程中累加ans值,然后当b-1或b等于0的时候特判一下,本蒟蒻果然没有摸清快速幂的原理。。。),然后又被自己的样例否决了。

      想不出正解我就只好暴力,然后在洛谷上水了30分,而我打出的伪正解只有10分

     正确思路:

    话说我似乎跑偏了,那么上最正确的解题思路(http://www.cnblogs.com/neopenx/p/4094705.html):  

    事实上最重要的是约数和公式:

    ①整数唯一分解定理:

    一个整数A一定能被分成:A=(P1^K1)*(P2^K2)*(P3^K3).....*(Pn^Kn)的形式。其中Pn为素数。

    如2004=(22)*3*167

    那么2004x=(22x)*(3x)*(167x)

    ②约数和公式

    对于一个已经被分解的整数A=(P1^K1)*(P2^K2)*(P3^K3).....*(Pn^Kn),

    有约数和S=(1+P12+P13+.....P1k1)*.....(1+Pn2+Pn3+.....Pnkn)。

    (1+P12+P13+.....P1k1)是一个等比数列,化简为(P1k1+1 -1)/(P1-1),由于有除法同余式,很容易想到乘法逆元。

    但是这题和HDU 1452不同,对于逆元表达式ax=1 mod n,乘法逆元存在的条件是gcd(a,n)=1,即a,n互质,但是这题的gcd(P1-1,9901)≠1, 所以不能用乘法逆元求解。

    所以有必要对等比数列求和公式改一改:

    (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质因数分解后,对于每一个质因数,累乘sum(质因数,次数)%mod即可,注意sum计算的时候都要mod防止溢出。

    注意一下A的范围,A=0或A=1时无法分解质因数,所以特判结果分别是0和1。

    根据以上定理,不难发现这道题非常之水,但是数论太渣,所以公式也没有推到底,再加上自己对快速幂的理解不够深刻,以我的智力是打不出正解的。。。

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 const long long mod=9901;
     4 using namespace std;
     5 long long zs[100001],gs[100001];
     6 long long n,m,p,Ans,s;
     7 long long mmp[1000001];
     8 void f(long long num) //求a的质因子和该质因子的个数 
     9 {
    10    long long i,j=0;
    11    for(i=2;i*i<=num;i++)
    12    {
    13        if(num%i==0)
    14        {
    15           long long count=0;
    16           zs[++j]=i;
    17           while(num%i==0)
    18           {
    19              count++;
    20              num/=i;
    21           }
    22           gs[j]=count;
    23     
    24        }
    25    }
    26    if(num>1)
    27    {
    28       zs[++j]=num;
    29       gs[j]=1;
    30    }
    31    s=j;
    32 }
    33 long long ksm(long long a,long long b) //快速幂,注意要边乘边模 
    34 {
    35     long long ans=1,base=a;
    36     long long f=0;
    37     while(b>0)
    38     {
    39         if(b%2!=0)
    40         ans=(ans*base)%mod;
    41         base=(base*base)%mod;
    42         b/=2;
    43     }
    44     return ans;
    45 }
    46 long long sum(long long p,long long k) //递推求约数和公式前一部分 
    47 {
    48     if(k==0) return 1;
    49     if(k%2) return ((sum(p,k/2)*(1+ksm(p,k/2+1)))%mod);
    50     else return ((sum(p,k/2-1)*(1+ksm(p,k/2+1))+ksm(p,k/2))%mod);
    51 }
    52 int main()
    53 {
    54    scanf("%lld%lld",&n,&m);
    55    Ans=1;
    56    if(m==0) //特判一下 
    57    {
    58       printf("1");
    59       return 0;
    60    }
    61    f(n);
    62    for(int i=1;i<=s;i++)
    63    {
    64       Ans=(Ans*(sum(zs[i],gs[i]*m)%mod))%mod; //约数和公式 
    65    }
    66    printf("%lld",Ans);
    67    return 0;
    68 }

     

    这道题似乎有三种做法,大部分是用的以上这种,毕竟很好想到,若是知道约数和公式就非常轻松了,不知道约数和公式也可以推出来(像我这种地表最弱蒟蒻就算了)

    还有一种较为常见的就是逆元,但我一个同学说他直接用快速幂求sum(a1,(k1^b)%mod)过了。。。

    这篇博客我逼逼得有点多,见谅。

     

       

    转载请注明出处:http://www.cnblogs.com/drurry/
  • 相关阅读:
    [LeetCode]113. Maximum Depth of Binary Tree二叉树的最大深度
    [LeetCode]112. Maximum Subarray最大和连续子序列
    [LeetCode]111. Find Minimum in Rotated Sorted Array II旋转数组最小值II
    [LeetCode]110. Find Minimum in Rotated Sorted Array旋转数组最小值
    [LeetCode]109. Construct Binary Tree from Inorder and Postorder Traversal由中序序列和后序序列重建二叉树
    [LeetCode]108. Construct Binary Tree from Preorder and Inorder Traversal由前序序列和中序序列重建二叉树
    [LeetCode]107. Best Time to Buy and Sell Stock III股票买卖III
    [LeetCode]106. Best Time to Buy and Sell Stock II股票买卖II
    [LeetCode]105. Word Search单词查找
    一些杂事之后,该收心了
  • 原文地址:https://www.cnblogs.com/drurry/p/7668213.html
Copyright © 2011-2022 走看看