POJ 1845 Sumdiv (因子和)
2015-04-25 00:00
323 查看
Sumdiv
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
Sample Output
这个题和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][1]代表这个素数的次数。
另给出HDU 1452题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1452
关于HDU 1452题目的补充知识:/article/8835433.html
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 15404 | Accepted: 3800 |
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][1]代表这个素数的次数。
#include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> 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<tot;i++) divi[i][1]*=B; for(i=0;i<tot;i++){ res=(res*cal(divi[i][0],divi[i][1]))%MOD; } printf("%I64d\n",res); } return 0; }
另给出HDU 1452题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1452
关于HDU 1452题目的补充知识:/article/8835433.html
相关文章推荐
- POJ 1845-Sumdiv【经典数学题目---求因子和】
- POJ 1845 Sumdiv 求幂级数的因子和+二分
- POJ 1845 Sumdiv(因子分解+快速幂+二分求和)
- POJ 1845 Sumdiv(求阶乘的因子和)
- POJ1845 Sumdiv 费马小定理+欧拉函数+素因子分解
- POJ 1845 Sumdiv(求阶乘的因子和)
- poj-1845 Sumdiv && nyoj - 928 小M的因子和
- POJ1845 Sumdiv【快速模幂+素因子分解+等比数列+二分法】
- poj 1845 Sumdiv (算术基本定理求一个数因子和)
- poj_1845 Sumdiv(素因子分解+快速幂+约数和+二分求等比数列和)
- poj1845——Sumdiv(数论+幂的因子和)
- POJ 1845 Sumdiv (因子和)
- poj-1845 Sumdiv (逆元+费马小定理+因子和)
- POJ 1845 Sumdiv (求某个数的所有正因子的和)
- [ACM] POJ 1845 Sumdiv(求A的B次方的所有因子的和,一大堆数学公式...,可做模板)
- A^B所有因子和(poj1845 Sumdiv)
- POJ 1845-Sumdiv【经典数学题目---求因子和】
- POJ 1845 --Sumdiv 约数基本定理+乘法逆元
- poj 1845 Sumdiv 素数筛+快速幂求逆元+二分乘法
- (POJ - 1845)Sumdiv(分治法/费马小定理+快速幂)