POJ 1845 Sumdiv
2014-02-22 08:47
183 查看
算是一道数学题。
首先,由唯一分解定理,可以将任意一个数分解为a=p1^a1*p2^a2*....*pk^ak。那么,此时对应的所有因子的和应该是:(1+p1+p1^2+p1^3+....+p1^a1)*.....*(1+pk+pk^2+...+pk^ak)。这个式子还是很好理解的,对于a的一个因子,它对pi一共有ai+1种选择方式。
之后这题目的关键就是求1+pk+pk^2+...+pk^ak。
主要有两种方法:
1.二分求解,定义cal(pk,ak)=1+pk+pk^2+...+pk^ak,当ak是奇数的时候cal(pk,ak)=cal(pk,ak/2)*(1+pow_mod(pk,ak/2+1));当ak是偶数的时候,
cal(pk,ak)=cal(pk,ak-1)+pow_mod(pk,ak)。
2.利用乘法逆元。注意到该数列是等比数列,那么cal(p,k)=(p^(ak+1)-1)/(p-1),那么就只要求p-1关于mod的乘法逆元就可以解决了,但求逆元的时候要注意p-1
是mod的倍数的情况。
首先,由唯一分解定理,可以将任意一个数分解为a=p1^a1*p2^a2*....*pk^ak。那么,此时对应的所有因子的和应该是:(1+p1+p1^2+p1^3+....+p1^a1)*.....*(1+pk+pk^2+...+pk^ak)。这个式子还是很好理解的,对于a的一个因子,它对pi一共有ai+1种选择方式。
之后这题目的关键就是求1+pk+pk^2+...+pk^ak。
主要有两种方法:
1.二分求解,定义cal(pk,ak)=1+pk+pk^2+...+pk^ak,当ak是奇数的时候cal(pk,ak)=cal(pk,ak/2)*(1+pow_mod(pk,ak/2+1));当ak是偶数的时候,
cal(pk,ak)=cal(pk,ak-1)+pow_mod(pk,ak)。
2.利用乘法逆元。注意到该数列是等比数列,那么cal(p,k)=(p^(ak+1)-1)/(p-1),那么就只要求p-1关于mod的乘法逆元就可以解决了,但求逆元的时候要注意p-1
是mod的倍数的情况。
#include "iostream" #include "cstdio" #include "cmath" #include "algorithm" #include "map" #define LL long long using namespace std; #define MOD 9901 //返回ab mod n LL mul_mod(LL a,LL b,LL c) { LL ret=0,tmp=a%c; while(b) { if(b&0x1)if((ret+=tmp)>=c)ret-=c; if((tmp<<=1)>=c)tmp-=c; b>>=1; } return ret; } //快速幂 LL pow_mod(LL a,LL p,LL n){ if(p==0) return 1%n; LL ans=pow_mod(a,p/2,n); ans=mul_mod(ans, ans, n); if(p%2==1) ans=mul_mod(ans, a, n); return ans%n; } LL prime[1111]; LL t[1111]; LL solve(LL p,LL t){ if(t==0) return 1; if(t==1) return (1+p)%MOD; if(t%2==1){ return solve(p,t/2)*(pow_mod(p,t/2+1,MOD)+1)%MOD; } else return (solve(p,t-1)+pow_mod(p,t,MOD))%MOD; } int main(){ LL a,b; cin>>a>>b; int cnt=0; if(a==0){ printf("0\n"); return 0; } if(b==0){ printf("1\n"); return 0; } LL tem=a; LL high=(LL)sqrt((double)a)+10; for(int i=2;i<=high;i++){ if(tem==1) break; if(tem%i==0){ prime[cnt]=i; while(tem%i==0){ tem/=i; t[cnt]++; } cnt++; } } if(tem!=1){ prime[cnt]=tem; t[cnt++]=1; } LL ans=1; //printf("%lld\n",prime[0]); //printf("%lld\n",solve(2,3)); //for(int i=0;i<cnt;i++){ //printf("%lld %lld\n",prime[i],t[i]); //} for(int i=0;i<cnt;i++){ ans=(ans*solve(prime[i]%MOD,t[i]*b))%MOD; } printf("%lld\n",(ans+MOD)%MOD); return 0; }
相关文章推荐
- POJ 1845 Sumdiv 笔记
- poj 1845 Sumdiv(所有约数的和)
- poj 1845 Sumdiv 素数筛+快速幂求逆元+二分乘法
- (POJ - 1845)Sumdiv(分治法/费马小定理+快速幂)
- POJ 1845 Sumdiv (因子和)
- POJ 1845 Sumdiv 求某数的幂取模
- Sumdiv POJ - 1845 A^B的所有约数之和
- POJ 1845 Sumdiv(快速幂取模+快速分解因式)
- POJ 1845 Sumdiv(求阶乘的因子和)
- poj 1845 Sumdiv (同余定理,快速幂取余)
- 【数论】【poj1845】Sumdiv
- poj1845 Sumdiv
- poj 1845 Sumdiv --- 因数分解
- poj 1845 Sumdiv [素数筛+母函数]
- POJ1845 Sumdiv 费马小定理+欧拉函数+素因子分解
- poj 1845 Sumdiv 数论--等比数列和(逆元或者递归)
- poj 1845 Sumdiv (数论)
- poj 1845 Sumdiv
- POJ 1845 Sumdiv(求阶乘的因子和)
- POJ 1845 Sumdiv (快速幂+质因数+约数和公式+同余模)