POJ——1845 Sumdiv (欧拉筛+快速幂+递归二分)

Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).

Input

The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.

Output

The only line of the output will contain S modulo 9901.

Sample Input

2 3

Sample Output

15

Hint

2^3 = 8. 
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次方的约数和。

题解:

这道题涉及到的知识:
1. 整数的唯一分解定理:

      任意正整数都有且只有一种方式写出其素因子的乘积表达式。

      A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数

2.约数和公式:

对于已经分解的整数A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)

有A的所有因子之和为:

 S = (1+p1+p1^2+p1^3+...p1^k1) * (1+p2+p2^2+p2^3+….p2^k2) * (1+p3+ p3^3+…+ p3^k3) * .... * (1+pn+pn^2+pn^3+...pn^kn)

所以A的B次方=(p1^ (k1*B) )*(p2^ (k2*B) )*(p3^ (k3*B) )*....*(pn^( kn*B) )

S = (1+p1+p1^2+p1^3+...p1^(k1*B)) * (1+p2+p2^2+p2^3+….p2^(k2*B)) * (1+p3+ p3^3+…+ p3^ (k3*B)) * .... * (1+pn+pn^2+pn^3+...pn^( kn*B))

公式记住就好了!!!

3.同余模公式:

(a+b)%m=(a%m+b%m)%m

(a*b)%m=(a%m*b%m)%m

4.二分求等比数列和,也可以逆元。

因为这个题目有1这一项所以第4个知识点反着用。

其他注意看代码注释!

#include <iostream>
using namespace std;
typedef long long ll;
const int mod=9901;
const int MAX = 1e6+100;
int pr[MAX];
bool vis[MAX];
struct hh{
	int ji;
	int sum;
}w[MAX];
ll quick(ll a,ll b,ll c){//快速幂 
	ll ans=1;
	while(b){
		if(b&1) ans=(ans*a)%c;
		b>>=1;
		a=(a*a)%c;
	}
	return ans%c;
}
void getpr(){ //欧拉筛素数 时间复杂度O(n) 
	int cnt=0;
	vis[0]=vis[1]=true;
	for (int i = 2; i < MAX;i++){
		if(!vis[i]) pr[cnt++]=i;
		for (int j = 0; j < cnt&& i*pr[j]< MAX;j++){
			vis[i*pr[j]]=true;
			if(i%pr[j]==0) break;
		}
	}
}
ll jisuan(ll a,ll b ){//递归二分求等比数列 1+p+p^2+p^3+…+p^n 
	if(b==0) return 1;
	else if(b&1) return jisuan(a,b/2)*(1+quick(a,b/2+1,mod))%mod;
	else return (jisuan(a,b/2-1)*(1+quick(a,b/2+1,mod))+quick(a,b/2,mod))%mod;
}
int main(){
	ll a,b;
	getpr();
	cin >> a >> b;
	int ans=0;
	for (int i = 0; pr[i]*pr[i] <= a;i++){//分解质因数
		if(a%pr[i]==0){
			w[ans].ji=pr[i];
			while(a%pr[i]==0){
				a/=pr[i];
				w[ans].sum++;
			}
			ans++;
		}
	}
	if(a!=1){//如果本身是质数加特判
		w[ans].ji=a;
		w[ans].sum++;
		ans++;
	}
	ll cnt=1;
	for (int i = 0; i < ans;i++){
		cnt=cnt*jisuan(w[i].ji,w[i].sum*b)%mod;
	}
	cout << cnt << endl;
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心脏dance

如果解决了您的疑惑,谢谢打赏呦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值