题目大意
求 A B mod 9901 A^B~\text{mod }9901 AB mod 9901的值。
题目解答
先对
A
A
A 进行质因数分解,可以得到
A
=
p
1
c
1
p
2
c
2
.
.
.
p
n
c
n
A=p_1^{c_1}p_2^{c_2}...p_n^{c_n}
A=p1c1p2c2...pncn 。
那么对于
A
B
A^B
AB 而言它的质因数分解应该是
A
=
p
1
c
1
B
p
2
c
2
B
.
.
.
p
n
c
n
B
A=p_1^{c_1B}p_2^{c_2B}...p_n^{c_nB}
A=p1c1Bp2c2B...pncnB 。
由乘法分配律可知
A
B
A^B
AB 全部的因数之和应该是
∏
i
=
1
n
∑
j
=
0
c
i
B
p
i
\prod_{i=1}^{n}\sum_{j=0}^{c_iB}p_i
i=1∏nj=0∑ciBpi
。
注意到每一个 Σ \Sigma Σ 都是一个等比数列,但是 9900 9900 9900 不是质数,所以不能求逆元。
这时候我们就可以引入分治法来解决问题。
假设 c i B = k c_iB = k ciB=k , Σ \Sigma Σ 部分我们用 s u m ( p , k ) sum(p,k) sum(p,k) 代替。
当 k k k 为奇数时,展开 s u m ( p , k ) sum(p,k) sum(p,k) 得 ( 1 + p + p 2 + p 3 + . . . + p k ) (1+p+p^2+p^3+...+p^k) (1+p+p2+p3+...+pk)。
提出一个 p k + 1 2 p^{\frac{k+1}{2}} p2k+1 得原式 = ( 1 + p + p 2 + . . . + p k − 1 2 ) × ( 1 + p k + 1 2 ) = (1+p+p^2+...+p^{\frac{k-1}{2}})\times{(1+p^{\frac{k+1}{2}})} =(1+p+p2+...+p2k−1)×(1+p2k+1)
= s u m ( p , ( k − 1 ) / 2 ) × ( 1 + p k + 1 2 ) =sum(p,(k-1)/2)\times{(1+p^{\frac{k+1}{2}})} =sum(p,(k−1)/2)×(1+p2k+1) 。
类似的,当 k k k 为偶数时,原式 = s u m ( p , k / 2 − 1 ) × ( 1 + p k 2 ) + p k =sum(p,k/2-1)\times(1+p^{\frac{k}{2}})+p^k =sum(p,k/2−1)×(1+p2k)+pk 。
其中幂运算可以用快速幂来解决。时间复杂度应为 O ( A log 2 B ) O(A\log^2B) O(Alog2B)。
技术细节
1.POJ 不支持万能头和 auto。
2.在分解质因数时只能用 O ( n ) O(\sqrt{n}) O(n) 的复杂度,不可偷懒。
3.建议配合 map 食用质因数分解。
代码实现
//1.NO BITS/STDC++.H
//2.USE THE BEST ALGORITHM YOU KNOW
//3.NO AUTO
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
#define P 9901
ll a,b;
map<ll,ll> pri;
ll qpow(ll x,ll y)
{
ll r=1;
// x%=P;
while(y)
{
if(y&1) r=r*x%P;
x=x*x%P,y>>=1;
}
return r;
}
ll sigma(ll x,ll y)
{
if(y==0) return 1;
if(y&1)
{
return /*r=*/((qpow(x,(y+1)>>1)+1)%P*sigma(x,(y-1)>>1)%P);
}
else
{
return /*r=*/((qpow(x,y>>1)+1)%P*sigma(x,(y>>1)-1)%P+qpow(x,y))%P;
}
// cout<<x<<' '<<y<<' '<<r<<endl;
}
int main()
{
scanf("%lld %lld",&a,&b);
if(a==0)
{
printf("0\n");
return 0;
}
ll sum=1;
for(ll i=2;i<=a/i;i++)
{
while(a%i==0)
a/=i,++pri[i];
}
if(a!=1)
pri[a]++;
for(map<ll,ll>::iterator i=pri.begin();i!=pri.end();i++)
{
sum*=sigma(i->first,i->second*b)%P;
sum%=P;
}
printf("%lld\n",sum);
return 0;
}