设为首页 加入收藏

TOP

POJ 1845 Sumdiv (因子和)
2015-11-21 01:03:57 来源: 作者: 【 】 浏览:2
Tags:POJ 1845 Sumdiv 因子
Sumdiv
Time Limit: 1000MS ? Memory Limit: 30000K
Total Submissions: 15404 ? Accepted: 3800

Description

Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).

Input

The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.

Output

The only line of the output will contain S modulo 9901.

Sample Input

2 3

Sample Output

15
这个题和HDU的1452基本上一样,只不过这里是HDU的 推广
先说这个题的解题步骤: ① 将A分解A=(p1^a1)*(p2^a2)*.....*(pk^ak),那么A^B就是A^B=[p1^(a1*B)] * [p2^(a2*B)] *.....*[pk^(ak*B)] ② 根据约数和的公式求和S并mod9901 别急,下面还有一些细节问题:
这个题我一开始就是先分解,然后按约数和的公式算.但是一直WA,我改了许多地方都不行。 如果一个数n=(p1^a1)*(p2^a2)*.....*(pk^ak) 约数和s=(p1^(a1+1)-1)/(p1-1) * (p2^(a2+1)-1)/(p2-1) *.....* (pk^(ak+1)-1)/(pk-1) 我就是按这个求s的公式算的,但是一直不对,肯定是因为这个公式中涉及到了除法,虽然在模运算中出现除法可以借助逆元来解决,但是因为求逆元是有条件限制的(a在模m意义下存在逆元的充要条件是a和m互素),我想是肯定是在处理这个地方的时候一直没处理好,所以一直WA。
其实是我忽略了另一个公式,我上面给的求s公式是变形之后的,变形之前是: s=(1+p1+p1^2+p1^3+...p1^a1) * (1+p2+p2^2+p2^3+….p2^a2) * (1+p3+ p3^3+…+ p3^a3) * .... * (1+pk+pk^2+pk^3+...pk^ak) 这个公式是不涉及除法的,用起来会很舒服。(而对这个公式每个括号里都是一个等比数列,分别对其求和就是上面的那个带除法的公式)。 至此问题就明了了。
那么就抛开这个题看下面的知识: 类似于这样的一个问题:S(k)=A^0+A^1+A^2+....+A^k的快速求和。 方法:二分+递归求解。 下面看个简单例子: ① k=4为偶数 A^0 + A^1 + A^2 + A^3 + A^4 =(A^0 + A^1)+A^2 + A^3(A^0 + A^1)=(1+A^3)*[A^0 + A^1]+A^2=(1+A^(k/2+1))*S(k/2-1)+A^(n/2) ② k=5为奇数 A^0 + A^1 + A^2 + A^3 + A^4 + A^5
=[A^0 + A^1 + A^2] + A^3*[A^0 + A^1 + A^2] = (1+A^3)*[A^0 + A^1 + A^2] = (1+A^(k/2+1))*S(k/2) 上面式子中,蓝色部分用快速幂,红色部分继续递归,这样就可以快速求出S(k)了。 递归出口n==0 return 1;
代码中divi[i][0]代表第i个素因子,divi[i][0]代表这个素数的次数。
#include 
  
   
#include 
   
     #include 
    
      #include 
     
       using namespace std; typedef __int64 ll; const int MOD=9901; ll divi[10000][2],tot; ll quick_mod(ll a,ll b){ //a^b%MOD ll res=1; a%=MOD; while(b){ if(b&1) res=(res*a)%MOD; b/=2; a=(a*a)%MOD; } return res; } ll cal(int p,int n){ if(n==0) return 1; if(n&1) return (1+quick_mod(p,n/2+1))*cal(p,n/2)%MOD; else return ((1+quick_mod(p,n/2+1))*cal(p,n/2-1)+quick_mod(p,n/2))%MOD; } void pre_solve(ll n){ ll i; tot=0; for(i=2;i*i<=n;){ if(n%i==0){ divi[tot][0]=i; divi[tot][1]=0; do{ n/=i;divi[tot][1]++; }while(n%i==0); tot++; } if(i==2) i++; else i+=2; } if(n>1){ divi[tot][0]=n;divi[tot][1]=1;tot++; } } int main() { ll A,B,i,res; while(scanf("%I64d%I64d",&A,&B)!=EOF){ if(A==0){ //别忘了特判 printf("0\n");continue; } if(A==1 || B==0){ printf("1\n");continue; } pre_solve(A); res=1; for(i=0;i
       
      
     
    
   
  
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C++ 初始化形式、变量初始化规则.. 下一篇poj 3744 Scout YYF I 概率dp+矩..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: