题意: 求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; }