Sumdiv POJ 1845

传送门

题目翻译,不想写不想写
A B A^{B} AB的所有约数之和mod 9901 9901 9901的值

根据约数和定理, A B A^{B} AB的因子和为 ( 1 + p 1 + p 1 2 + . . . + p 1 c 1 ∗ B ) ∗ . . . ∗ ( 1 + p m + p m 2 + . . . + p m c m ∗ B (1+{p_{1}}+{p_{1}^{2}}+...+{p_{1}}^{c_{1}*B})*...*(1+{p_{m}}+{p_{m}^{2}}+...+{p_{m}}^{c_{m}*B} (1+p1+p12+...+p1c1B)...(1+pm+pm2+...+pmcmB
括号中的每一项都是一个等比数列,可以使用等比数列前N项和公式求值。而前N项和公式需要除法取模,因此需要求分母 1 − p i 1-p_{i} 1pi在模 9901 9901 9901下的逆元,逆元根据费马小定理求解。

如果逆元存在,则求逆元,然后快速幂乘法运算
如果逆元不存在,即 1 − p 1-p 1p 9901 9901 9901的倍数,则 p % 9901 = 1 p \%9901=1 p%9901=1,即该等比数列的和对 9901 9901 9901取模后的值为项数N,即 c i + 1 c_{i}+1 ci+1

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
typedef long long ll;
ll p[33], c[33], ind;
ll a, b;
ll qc(ll x,ll y,ll mod)
{
    
    
	// 快速乘
    return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;     
}
ll qpow(ll x, ll y, ll m){
    
    
	// 快速幂
	ll res = 1;
	res %= m;
	while (y){
    
    
		if(y & 1){
    
    
			res = qc(res, x, m);
		}
		y >>= 1;
		x = qc(x, x, m);
	}
	return res % m;
}
void divide(ll n){
    
    
	// 算数基本定理
	ind = 0;
	mem(p, 0);
	mem(c, 0);
	ll temp = n;
	for (int i = 2; i * i <= temp; i++){
    
    
		if (n % i == 0){
    
    
			p[++ind] = i;
			while (n % i == 0){
    
    
				n /= i;
				c[ind]++;
			}
		}
	}
	if (n > 1){
    
    
		p[++ind] = n;
		c[ind]++;
	}
	for (int i = 1; i <= ind; i++){
    
    
		c[i] *= b;
	}
}
ll euler(ll n){
    
    
	// 欧拉函数
	ll ans = n;
	for (int i = 2; i * i <= n; i++){
    
    
		if (n % i == 0){
    
    
			ans = ans * (n - 1) / n;
			while (n % i == 0){
    
    
				n /= i;
			}
		}
	}
	if (n > 1){
    
    
		ans = ans * (n - 1) / n;
	}
	return ans;
}
ll ans;
int main(){
    
    
	// freopen("in.in", "r", stdin);
	// freopen("out.out", "w", stdout);
	scanf("%lld %lld", &a, &b);
	divide(a);
	ans = 1;
	for (int i = 1; i <= ind; i++){
    
    
		if ((1 - p[i]) % 9901 == 0){
    
    
			// 逆元不存在
			ans = ans * ((c[i] + 1) % 9901);
			ans %= 9901;
		}
		else {
    
    
			// 逆元存在
			ll inv;
			inv = qpow(1 - p[i], (euler(9901) - 1) % 9901, 9901);
			ans = qc(ans, qc((1 - qpow(p[i],  c[i] + 1, 9901)), inv, 9901), 9901);
			ans %= 9901;
		}
	}
	printf("%lld\n", ans);
	return 0;
}

约数和定理简单证明如下
约数和定理证明

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/109087441