首页 > 代码库 > POJ 1845 - Sumdiv ( 数论 + 唯一分解定理 + 快速幂取模 )
POJ 1845 - Sumdiv ( 数论 + 唯一分解定理 + 快速幂取模 )
POJ 1845 - Sumdiv ( 数论 + 唯一分解定理 + 快速幂取模 )
这是一道数论的好题,需要较好的数学基础
题意: 给定A,B,求A^B的所有因数的和,再MOD 9901
分析:
这里用到了数论当中相当一部分知识
a. 唯一分解定理
任何一个整数都可以分解为若干个素数的幂的乘积的形式
A = ( p1 ^ q1 + p2 ^ q2 + ..... + pn ^ qn ) p为素数
A^B = ( p1 ^ (q1*B) + p2 ^ (q2*B) + ..... + pn ^ (qn*B) )
b. 约数和公式
Sum( A ) = ( 1 + p1 + p1^2 + .... + p1^q1 ) * ( 1 + p2 + p2^2 + .... + p2^q2 ) * ...... * ( 1 + pn + pn^2 +.....+ pn^qn )
Sum( A^B ) = (1 + p1 + p1^2 + .... + p1^(q1*B) ) * ( 1 + p2 + p2^2 + .... + p2^(q2*B) ) * ...... * ( 1 + pn + pn^2 +.....+ pn^(qn*B) )
c. 快速幂取模(略去)
d. 简单的模计算公式
(a*b)%M = (a%M)*(b%M)%M
e. 递归求解等比数列前n项和 (或者是用乘法逆元来求,还不会,马上补上)
( 1 + p1 + p1^2 + .... + p1^n ) 分奇偶进行讨论:
1.) n 为 奇数 ( n & 1 ), 总共有偶数项 ,假设n == 5
( 1 + p1 + p1^2 + p1^3 + p1^4 + p1^5 ) = ( 1 + p1 + p1^2 + p1^3 (1 + p1 + p1^2 ) )
=( 1 + p1 + p1^2 + p^(5/2+1) (1 + p1 + p1^2) )
=( 1+ p^(5/2+1) ) * (1 + p1 + p1^2 )
转化为一般式应该为
( 1 + p1 + p1^2 + .... + p1^n )
= ( 1 + p1 + p1^2 + .... + p1^(n/2) + p^(n/2+1) * (1 + p1 + p1^2 + ..... p1^(n/2)) )
=(1 + p^(n/2+1)) * (1 + p1 + p1^2 + ..... + p1^(n/2))
=(1 + fast_mod(p1,n/2+1) ) * sum(p1,n/2)
2.) n 为 偶数 总共有奇数项 ,假设n == 6
( 1 + p1 + p1^2 + p1^3 + p1^4 + p1^5 + p1^6 ) = ( 1 + p1 + p1^2 + p1^3 + p1^4 (1 + p1 + p1^2) )
=( 1 + p1 + p2 + p1^4( 1 + p1 + p2 ) + p1^3 )
=( (1 + p^4)( 1 + p1 + p2 ) + p1^3 )
转化为一般式子为
( 1 + p1 + p1^2 + .... + p1^n )
=( 1 + p1^(n/2+1) ) * ( 1 + p1 + p2 + ... + p^(n/2-1) ) + p1^(n/2)
=( 1 + fast_mod(p1,n/2+1) )* sum( p1, n/2-1 ) + fast_mod(p1,n/2)
f.乘法逆元,弱菜太弱,还不会,马上补上
首先我们需要知道等比数列的前N项和
然后除以(1-q)转化为乘法逆元来做
最后给出代码
/* ***********************************************ID : whiteblock63LANG : G++PROG : POJ - 1845 SumdivDATE : 2014-10-06 15:56:09************************************************ */#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <cmath>#define CLR( a, b ) memset( a, b, sizeof(a) )using namespace std;typedef long long LL;typedef unsigned long long ULL;#define MAXN 10000#define MOD 9901LL A, B; //fast_pow_modLL fast_mod( LL a, LL b ){ LL ans = 1; a = a % MOD; while( b ){ if( b & 1 ) ans = ans * a % MOD; a = a * a % MOD; b >>= 1; } return ans;}LL factors[MAXN][2];int fn;//分解质因数void gaoji( LL x ){ fn = 0; for( LL i = 2; i*i <= x; ++i ){ if( x % i ) continue; factors[++fn][0] = i; factors[fn][1] = 0; while( x % i == 0 ){ factors[fn][1]++; x /= i; } } if( x != 1 ){ factors[++fn][0] = x; factors[fn][1] = 1; }}//递归求解等比数列LL sum( LL p, LL n){ if( n == 0 ) return 1; if( p == 0 ) return 0; if( n & 1 ) return ( sum(p, n/2) * (1 + fast_mod( p, n/2 + 1 )) ) % MOD; else return ( sum(p, n/2-1) * (1 + fast_mod( p, n/2 + 1 )) + fast_mod( p, n/2 ) ) % MOD;}void Orz(){ scanf( "%lld %lld", &A, &B); gaoji( A ); LL ans = 1; for( int i = 1; i <= fn; ++i ){ ans = ans * ( sum( factors[i][0], B*factors[i][1] ) ) % MOD; } printf("%lld\n", ans);}int main(){ Orz(); return 0;}
POJ 1845 - Sumdiv ( 数论 + 唯一分解定理 + 快速幂取模 )