Sumdiv Page17 分治/逆元
书上的分治方法就不提了
加深一下这题的数论解法
先将A做唯一分解
对于 p 1 b k 1 − 1 p 1 − 1 % 9901 {{p_1^{bk_1}-1}\over p_1-1}\%9901 p1−1p1bk1−1%9901,可以求出 p 1 − 1 p_1-1 p1−1在模 9901 9901 9901意义下的逆元(由于 p 1 p_1 p1肯定是个质数,所以可以用费马小定理求解逆元)
但是有逆元的前提是 p 1 − 1 p_1-1 p1−1与 9901 9901 9901互质,由于 9901 9901 9901本身是个质数,所以他们两个数不互质的数学表达式为 ( p 1 − 1 ) % 9901 = 0 ({p_1-1})\%9901=0 (p1−1)%9901=0。这种情况下的处理为将等比公式还原回去,即计算 ( 1 + p 1 + p 1 2 + . . . p 1 b k 1 ) % m o d (1+p_1+{p_1}^2+...{p_1}^{bk_1})\%mod (1+p1+p12+...p1bk1)%mod,由于 p 1 % 9901 = 1 , p 1 2 % 9901 = p 1 % 9901 × p 1 % 9901 = 1 × 1 = 1 , . . . p 1 b k 1 % 9901 = 1 p_1\%9901=1,{p_1}^2\%9901=p_1\%9901×p_1\%9901=1×1=1,...{p_1}^{bk_1}\%9901=1 p1%9901=1,p12%9901=p1%9901×p1%9901=1×1=1,...p1bk1%9901=1,故其结果为 b k 1 + 1 bk_1+1 bk1+1个 1 1 1相加
代码:
#define ll long long
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define WW(x) printf("%lld\n",x)
const ll mod=9901;
int mm,a,b;
struct node
{
ll x,num;
}p[maxn];
ll qpow(ll a,ll b,ll mod)
{
ll res=1;
while(b)
{
if (b&1)res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
void solve(int x)
{
rep(i,2,int(sqrt(x)))
{
if (x%i==0)
{
ll num=0;
while(x%i==0)
{
x/=i;num++;
}
p[mm].x=i;
p[mm++].num=num;
}
}
if (x>1)
{
p[mm].x=x;
p[mm++].num=1;
}
}
int main()
{
while(~scanf("%d%d",&a,&b))
{
mm=0;
solve(a);
ll ans=1;
repp(i,0,mm)
{
ll x=p[i].x;
ll num=p[i].num;
if ((x-1)%mod==0)
{
ans=ans*(1+b*num)%mod;
}
else
{
ll inv=qpow(x-1,mod-2,mod);
ll pow=qpow(x,b*num+1,mod)-1;
ans=ans*pow%mod*inv%mod;
}
}
while(ans<0)ans+=mod;
WW(ans);
}
}