约数之和「递归+数论」

约数之和

题目描述:

输入A,B,求 A B A^B AB的所有约数之和在 m o d 9901 mod 9901 mod9901下的值

思路:

根据唯一分解定理可以把A分解成:

A = a 1 p 1 ∗ a 2 p 2 ∗ . . . ∗ a k p k A = a_1^{p_1}*a_2^{p_2}*...*a_k^{p_k} A=a1p1a2p2...akpk

A B = a 1 B ∗ p 1 ∗ a 2 B ∗ p 2 ∗ . . . ∗ a k B ∗ p k A^B = a_1^{B*p_1}*a_2^{B*p_2}*...*a_k^{B*p_k} AB=a1Bp1a2Bp2...akBpk

所以约数之和为
S = ( a 1 0 + a 1 1 + . . + a 1 B ∗ p 1 ) ∗ ( a 2 0 + a 2 1 + . . + a 2 B ∗ p 2 ) + . . . + ( a k 0 + a k 1 + . . + a k B ∗ p k ) S = (a_1^0+a_1^1+..+a_1^{B*p1})*(a_2^0+a_2^1+..+a_2^{B*p2}) +...+ (a_k^0+a_k^1+..+a_k^{B*pk}) S=(a10+a11+..+a1Bp1)(a20+a21+..+a2Bp2)+...+(ak0+ak1+..+akBpk)
所以我们只需要解决因数分解以及求类似 ( a 1 0 + a 1 1 + . . + a 1 B ∗ p 1 ) (a_1^0+a_1^1+..+a_1^{B*p1}) (a10+a11+..+a1Bp1)

假设 s u m ( a , x ) = ( a 0 + a 1 + . . . + a x − 1 ) sum(a,x) = (a^0+a^1+...+a^{x-1}) sum(a,x)=(a0+a1+...+ax1)

  • x是偶数时,利用指数相乘时底数不变,指数想加的方法可以得出 s u m ( a , x ) = s u m ( a , x / 2 ) + s u m ( a , x / 2 ) ∗ a x / 2 sum(a,x) = sum(a, x/2) + sum(a, x/2)*a^{x/2} sum(a,x)=sum(a,x/2)+sum(a,x/2)ax/2
  • x是奇数时,只需要把最后一项拿出来,则可以利用偶数方法计算, s u m ( a , x ) = s u m ( a , x − 1 ) ∗ a x − 1 sum(a, x) = sum(a, x-1) * a^{x-1} sum(a,x)=sum(a,x1)ax1

这其实就是递归的过程

当然,这个题的模数只有9901,任何一个数字的幂次最多经过9900次就会产生重复,所以我们可以记录循环节来直接计算 s u m ( a , x ) sum(a,x) sum(a,x),计算一次最多需要循环9901次,A最多也就十几个质因子,所以复杂度差不多是1e5级别的

#include
using namespace std;

#define endl '\n'
#define io ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define m_p(a, b) make_pair(a, b)
typedef long long ll;
typedef pair<int, int> pii;
#define MAX 300005
#define mod 9901
int n, m, d, x, k;
ll sum[MAX];

ll p_qow(ll a, ll b){
	ll ans = 1;
	while(b){
		if(b&1)ans = (ans * a) % mod;
		(a *= a) %= mod;
		b >>= 1;
	}
	return ans;
}

ll fuck(ll x, ll k){
	if(k == 1)return 1;
	if(k % 2 == 0){
		return (fuck(x, k/2) * (1ll + p_qow(x, k/2)))%mod; 
	}
	else return (fuck(x, k-1) + p_qow(x, k-1))%mod;
}


void work(){
	cin >> n >> m;
	ll ans = 1ll;
	for(ll i = 2; i * i <= n; ++i){
		if(n % i == 0){
			ll num = 0;
			while(n % i == 0){
				++num;
				n /= i;
			}
			num *= m;
			(ans *= fuck(i, num+1))%=mod;
		}
	}
	if(n > 1)(ans *= fuck(n, 1+m))%=mod;
	if(!n)cout << 0 << endl;
	else cout << ans << endl;
}


int main(){
	//int t;cin >> t;while(t--)
	work();
	return 0;
}

你可能感兴趣的:(算法,数论,递归)