您的位置:首页 > 其它

POJ 1845 Sumdiv (因子和)

2015-04-25 00:00 323 查看
Sumdiv

Time Limit: 1000MSMemory Limit: 30000K
Total Submissions: 15404Accepted: 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][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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: