Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 18488 | Accepted: 4674 |
Description
Input
Output
Sample Input
2 3
Sample Output
15
Hint
The natural divisors (除数) of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).
题意:给你两个数,a,b问你a^b的约数的和是多少,A,B是很给力的5kW qwq。
思路:
要想求和就得先找出约数,当时是先发现了质数,当a为质数时,它的N次方的约数组成的序列就是一个公比为a的等比数列。(我还傻的以为就是求这个的等比数列的和QAQ,啊蠢死了,哇哇哇的)当然只限是质数,所以要把它扩展到一般的数。
1.最先想到的就是把这个数先因式分解掉,分解成n个质数相乘的样子。举个栗子:譬如6^2吧,先把6分解掉就是2*3.原式就是(2*3)^2.然后自然就是(2^2)*(3^2).
2.这时候我们就应该要好好想一想辣,首先就是2^2的因子有1,2,4。 3^2的因子有1,3,9。这时分别从两个数列中选取一个相乘所组成的数就是这个数的一个因子(这里读者需要自己好好想想呐)所以和的形式我们就可以写成(1+2+4)*(1+3+9)的形式。
3.分解的时候当然是需要先打一个素数表,因为范围是5kw,所以素数表的范围开个方就够辣,我这开的1w。分解到最后,a最后应该剩下一,特殊的情况就是这个数的素因子比我们素数表的范围大,可以确定的是剩下的因子不可能达到平方的状态,因为达到平方说明这个数超出了范围了,也就是这个数只可能剩下一个素因子了。最后计算和的时候加上这个素因子就可以了。分解时枚举素数的结束条件就是枚举的素数的平方已经比a大了,说明此时a为1或者a只剩下一个素因子。
4.然后就是怎么求括号里面的值,当然用等比数列的求和公式就可以解决,但是这个题是大数取模的题,所以我们需要用同余取模,并且公式里面有除法,所以我们还要用到逆元,因为m是个素数,所以我们直接用费马小定理就可以辣。计算的时候一定要用快速幂。
5.注意的是任何数的0次方都是1,1的任何次方都是1!(这里应该是没有太坑的数据,没有出现0^n这种)。
6.还有就是求逆元的时候,如果等比数列的(公比-1)(也就是除数)是mod(这里是9901)的倍数,那么逆元是无解的,此时可以想一下,取模之后这个数列就相当于公比为1的情况,所以和就是Sn=n。当然是取模后为1,并不是真的是1.
费马小定理(Fermat Theory)是数论中的一个重要定理,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=10000;
const int mod=9901;
bool prim[MAXN+10];
int p[MAXN];
int pcnt,cnt;
void get_prim()
{
int i,j;
pcnt=0;
for(i=2;i<=MAXN;++i)
{
if(!prim[i])
{
p[pcnt++]=i;
for(j=i<<1;j<=MAXN;j+=i)prim[j]=1;
}
}
}
int a,b;
int f(int a,int b)//快速幂求a^b
{
int base=a%mod;//a可能比较大,比如说50000000
int sum=1;
while(b)
{
if(b&1)sum=(sum*base)%mod;
base=(base*base)%mod;
b>>=1;
}
return sum;
}
void solve(int a,int b)
{
int ans=1;
int i;
for(i=0;p[i]*p[i]<=a;++i)//分解a为质数的乘积
{
if(a%p[i]==0)
{
int sum=0;
while(a%p[i]==0)
{
sum++;
a/=p[i];
}
if((p[i]-1)%mod==0)ans=(ans*(sum*b+1))%mod;//前面条件成立的时候逆元是无解的
else
{
int x1=f(p[i],sum*b+1);
x1=(x1+mod-1)%mod;//x1取完模之后可能为0
int x2=f(p[i]-1,mod-2);//x2为p[i]-1的逆元
ans=(ans*((x1*x2)%mod))%mod;
}
}
}
if(a>1)//如果a不为1
{
if((a-1)%mod==0)ans=(ans*(b+1))%mod;
else
{
int x1=f(a,b+1);
x1=(x1+mod-1)%mod;
int x2=f(a-1,mod-2);
ans=(ans*((x1*x2)%mod))%mod;
}
}
printf("%d\n",ans);
}
int main()
{
scanf("%d%d",&a,&b);
if(a<=1||b==0)puts("1");
else
{
get_prim();//素数打表
solve(a,b);
}
return 0;
}