题意: 求n^m的因子和
思路:
对n进行素因子分解。
n = p1^a1 * p2^a2 * .... * ps^as
σ(n) = ((p1^(a1+1)-1)/(p1-1) * ((p2^(a2+1)-1)/(p2-1) * .... * ((pj^(aj+1)-1)/(pj-1)) = Π(j=1 -> s) (pj^(aj+1)-1)/(pj-1)
因子和函数σ定义为整数n的所有正因子之和,记为σ(n)
τ(n) = (a1+1) * (a2+1) * ... * (as+1) = Π(j=1 -> s) (aj + 1)
因子个数函数τ定义为正整数n的所有正因子个数,记为τ(n)
Π:表示乘积的符号
这道的题的思路是 σ(n) = Π(j=1 -> s) (pj ^(aj+1)-1)/(pj-1)
则 σ(n^m) = Π(j=1 -> s) (pj^ (m*aj+1)-1)/(pj-1)
对n进行因子分解,然后计算。 在计算的时候,除法要取逆元来计算。然后分开计算,连乘会爆掉longlong的范围。
逆元 : 求解(a/b)%m,因为b可能会过大,会出线爆掉精度的问题
设c是b的逆元,则有 b*c≡1(mod m);
则(a/b)%m = (a/b)*1%m = (a/b)*b*c%m = a*c(mod m)
即 a/b的模等于 a* b的逆元 的模
求逆元的方法
1:费马小定理 模数p是素数, 则 x的逆元 为 x^(p-2)
2: 扩展欧几里得算法求逆元
3: 逆元线性筛
#include <stdio.h>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;
const LL mod = 1e9 + 7;
LL n, m;
LL T;
const long long N = 1e7 + 10;
LL prime[N/10];
bool isprime[N];
LL numprime = 0;
void doprime()
{
memset(isprime,true,sizeof(isprime));
isprime[0] = 0;
isprime[1] = 0;
for(LL i = 0; i < N; i++)
{
if(isprime[i])
{
prime[numprime++] = i;
for(LL j = i * i; j < N; j += i)
isprime[j] = 0;
}
}
}
LL a[1060]; /// 保存素因子
int b[1060]; /// 保存素因子的个数
int cnt;
void suanshu(long long n)
{
cnt=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i = 0; i < numprime && prime[i] * prime[i] <= n; i++)
{
if(n % prime[i] == 0)
{
a[cnt] = prime[i];
while(n % prime[i] == 0)
{
b[cnt]++;
n /= prime[i];
}
cnt++;
}
}
if(n!=1)
{
a[cnt] = n;
b[cnt++] = 1;
}
}
LL pow_4(LL a, LL b)
{
LL ans = 1;
while(b)
{
if(b&1)
{
ans = (ans * a) % mod;
b--;
}
b /= 2;
a = a * a % mod;
}
return ans ;
}
int main()
{
scanf("%lld",&T);
doprime();
LL Case = 1;
while (T--)
{
scanf("%lld%lld", &n, &m);
// 对n进行因子分解
suanshu(n);
LL sum = 1;
for(int i = 0; i < cnt; i++)
{
///printf("%lld %lld\n",a[i],b[i]);
sum = sum*(pow_4(a[i], m * b[i] +1) + mod - 1) % mod;
sum = sum*(pow_4(a[i] - 1,mod-2)+mod) % mod;
}
printf("Case %lld: ",Case++);
printf("%lld\n", sum % mod);
}
return 0;
}