题目链接:http://poj.org/problem?id=1845
一道不错的数论题,用到的知识比较多,表示也是看了题解之后才做出了这道题。之前对因子和还只是有那么一丁点概念,现在概念好像明朗了许多。
题意简单明了,求A^B的因子和,然后对9901取模。
先解释下因子和的概念,对于一个数N:
N的因子和为(1+p1+p1^2+…+p1^c1)*(1+p2+p2^2+…+p2^c2)*… *(1+pk+pk^2+…+pk^ck)
Pi表示N的第i种素因子,Ci表示N的第i种素因子的个数。
那么按照解题思路来说,我们要先将A分解素因子,进而将A分解成p1^c1+p2^c2+...+pk^ck的唯一分解方式,然后求每个素因子pi从0次幂到ci次幂的和,最终将这些和相乘得到结果。
那么,让我们由果溯因的推出顺序:
1.要想将所有幂次和相乘,我们只需一个for循环即可。
2.要想求某一个素因子pi,0到ci次幂的和,我们最容易想到的是等比求和公式,但是根据模运算的运算规则:
(a + b) % p = (a % p + b % p) % p (1)(a - b) % p = (a % p - b % p) % p (2)
(a * b) % p = (a % p * b % p) % p (3)a ^ b % p = ((a % p)^b) % p (4)
它与基本四则运算有些相似,但是除法例外。
所以等比求和公式因为包含除法而无法做到边算边取模,于是,我们应当采取一种分治的策略,来节省时间复杂度,并且保证该算法中不含有除法,即二分递归求解等比数列的和。
3.为了找到所有的素数p,我们需要对A进行分解素因子,时间复杂度是O(sqrt(n))。
4.在递归求和的过程中,必然要算到pi的某次幂,当这个幂次比较大或者求出幂的结果的时候,就需要用到快速幂取模了。
至此,此题已可解。
代码如下:
#include<cstdio>
#include<iostream>
using namespace std;
const __int64 mod=9901;
int p[10010],c[10010];
__int64 pow(__int64 a,__int64 b){//快速幂取模
__int64 r=1,base=a;
while(b!=0){
if(b&1) r=((r%mod)*(base%mod))%mod;
base=((base%mod)*(base%mod))%mod;
b>>=1;
}
return r;
}
__int64 sum(__int64 a,__int64 b){//递归求等比和
if(b==0)
return 1;
if(b&1)
return ((1+pow(a,b/2+1))%mod*sum(a,b/2)%mod)%mod;
else
return ((1+pow(a,b/2+1))%mod*sum(a,(b-1)/2)%mod+pow(a,b/2)%mod)%mod;
}
int main(){
__int64 A,B,ans;
int count;
while(~scanf("%I64d%I64d",&A,&B)){
count=1,ans=1;
for(int i=2;i*i<=A;i++){//分解素因子
if(A%i==0){
p[count]=i;
while(A%i==0){
A/=i;
c[count]++;
}
count++;
}
}
if(A!=1){
count++;
p[count]=A;
c[count]++;
}
for(int i=1;i<=count;i++)//将所有幂次和相乘
ans=(ans%mod*sum(p[i],B*c[i])%mod);
printf("%d\n",ans);
}
return 0;
}
表示最近对数论感了点兴趣,嗯,还真是东一榔头,西一扫帚...