约数之和。

约数之和

题意:

求出 a b a^b ab的约数之和。

思路:

将a分解质因数得 a = p 1 n u m 1 ∗ p 2 n u m 2 ∗ . . . . . . p n n u m n a=p_1^{num1}*p_2^{num2}*......p_n^{numn} a=p1num1p2num2......pnnumn,那么 a b a^b ab分解质因数就是 a = p 1 n u m 1 + b ∗ p 2 n u m 2 + b ∗ . . . . . . p n n u m n + b a=p_1^{num1+b}*p_2^{num2+b}*......p_n^{numn+b} a=p1num1+bp2num2+b......pnnumn+b,于是:约数之和就为 s u m = ( 1 + p 1 + p 1 2 + . . . + p 1 n u m 1 + b ) ∗ ( 1 + p 2 + p 2 2 + . . . + p 2 n u m 2 + b ) ∗ . . . ∗ ( 1 + p n + p n 2 + . . . + p n n u m n + b ) sum=(1+p_1+p_1^2+...+p_1^{num1+b})*(1+p_2+p_2^2+...+p_2^{num2+b})*...*(1+p_n+p_n^2+...+p_n^{numn+b}) sum=(1+p1+p12+...+p1num1+b)(1+p2+p22+...+p2num2+b)...(1+pn+pn2+...+pnnumn+b)
上面这个式子由乘法分配定理得到,可以很轻易的想到,要得到所有的约数,只需要让不同的质因数的不同次方相乘即可。
然后发现这个式子括号里的每一项都是等比数列,所以只需要用等比数列求和公式: s = a 1 ∗ ( 1 − q n ) / ( 1 − q ) s=a_1*(1-q^n)/(1-q) s=a1(1qn)/(1q),用到这里要稍微转换一下: s = a 1 ∗ ( q n − 1 ) / ( q − 1 ) s=a_1*(q^n-1)/(q-1) s=a1(qn1)/(q1)然后用快速幂逆元取模即可,要注意,当分子取模为0时,逆元是不存在的,但既然分子取模为0,即 a 1 ∗ ( q n − 1 ) a_1*(q^n-1) a1(qn1)% m o d = 0 mod=0 mod=0,因为这里 a 1 a_1 a1为1,所以 ( q n − 1 ) (q^n-1) qn1% m o d = 0 mod=0 mod=0,所以 q n q^n qn% m o d = 1 mod=1 mod=1,此时这个等比数列的值 s = 项 数 s=项数 s=

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod = 9901;

int cnt;
int pri[1000010];
int vis[1000010];
int ans[1000010];
int num[1000010];
ll qpow(ll a,ll b)
{
	ll res = 1;
	while(b)
	{
		if(b%2)res = res*a%mod;
		b = b>>1;
		a = a*a%mod;
	}
	return res;
}
void oula()
{
	for(int i = 2; i <= 1000000; i++)
	{
		if(!vis[i])pri[++cnt] = i;
		for(int j = 1; j <= cnt && pri[j]*i <= 1000000; j++)
		{
			vis[i*pri[j]] = 1;
		}
	}
}
int main()
{
	__int128 p;
	oula();
	ll a,b;
	cin>>a>>b;
	if(a == 0)
	{
		cout<<0<<endl;
		return 0;
	}
	int c = 0,now = a;
	for(int i = 1; i <= cnt; i++)
	{
		now = a;
		if(pri[i] > now)break;
		if(now%pri[i] == 0)ans[++c] = pri[i];
		while(now%pri[i]==0)
		num[c]++,now/=pri[i];
	}
	ll res = 1;
	for(int i = 1; i <= c; i++)
	{
		if((qpow(ans[i],b*num[i]+1)+mod-1)%mod != 0)
		res *= (qpow(ans[i],b*num[i]+1)+mod-1)%mod*qpow(ans[i]-1,mod-2)%mod;
		else res*=(num[i]*b+1)%mod; 
		res%=mod;
	}
	cout<<(res)%mod<<endl;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 题目描述: 编程读入两个正整数a,b,输出[a,b]区间内的所有亲和数对。亲和数对的含义是一对整数m和n,满足m的真约数之和等于n,同时n的真约数之和等于m。 解题思路: 首先,我们需要一个函数来求一个数的所有真约数之和。然后,我们可以遍历[a,b]区间内的所有数,对于每个数m,我们可以计算出其真约数之和sum_m,然后再遍历[a,b]区间内的所有数n,对于每个数n,我们可以计算出其真约数之和sum_n,如果sum_m等于n且sum_n等于m,则(m,n)是一个亲和数对,输出即可。 需要注意的是,题目中给出的数据范围是1≤a≤b≤10000,因此我们需要对每个数都计算其真约数之和,时间复杂度为O(n^2),可能会超时。因此,我们可以使用一个数组来记录每个数的真约数之和,这样可以将时间复杂度降为O(n)。 代码实现: ### 回答2: 什么是亲和数对? 亲和数对是指一对整数m和n,满足m的真约数之和等于n,同时n的真约数之和等于m。例如:220和284是一对亲和数对,因为220的真约数之和为284,284的真约数之和为220。 如何解决编程问题? 对于此问题,可以设置两个循环i和j来遍历[a,b]区间内的所有数对。在循环中,我们需要找出数i的所有真约数之和以及数j的所有真约数之和,并进行比较。如果这两个数相等,就说明它们是一对亲和数。 下面是代码示例: ```python def get_divisors_sum(num): """ 计算num的所有真约数之和 """ divisors_sum = 1 for i in range(2, int(num ** 0.5) + 1): if num % i == 0: divisors_sum += i if num // i != i: divisors_sum += num // i return divisors_sum a, b = map(int, input().split()) for i in range(a, b+1): for j in range(i+1, b+1): if get_divisors_sum(i) == j and get_divisors_sum(j) == i: print(i, j) ``` 需要注意的是,由于题目中给定的数据范围比较大 [1,2e6],因此在计算真约数之和时,应该使用优化的算法。上面的代码示例中,我们使用了较为高效的方法来计算真约数之和。 ### 回答3: 首先,我们需要明确什么是真约数。一个正整数的真约数是指除了它本身以外的所有因数。比如,6的真约数为1、2、3。 接下来,我们需要找出[a,b]区间内所有的亲和数对。我们可以用一个双重循环来枚举区间内的每一个数对,对于每个数对(m,n),我们需要分别求出它们的真约数和sum1和sum2,再判断是否满足亲和数对的条件。 具体地,我们可以使用一个函数get_div_sum(num)来获取一个数num的真约数之和。它的实现方式是将num从2到sqrt(num)的每一个因数加入sum中,并将num/i也加入sum中,最后再加上1(因为1是所有数的真约数),即为num的真约数之和。 下面是完整的代码实现: def get_div_sum(num): sum = 1 for i in range(2, int(num**0.5) + 1): if num % i == 0: sum += i + num // i if int(num**0.5)**2 == num: sum -= int(num**0.5) return sum a, b = map(int, input().split()) cnt = 0 for m in range(a, b + 1): n = get_div_sum(m) if m < n and get_div_sum(n) == m: print("{} {}".format(m, n)) cnt += 1 if cnt == 0: print("NONE") 注意,在循环枚举时,我们只需要对m<n的数对进行判断,因为m=n时显然不满足亲和数对的条件。另外,需要特别处理m=n的情况,因为此时如果判断成立,会输出重复的数对,在这里我们只输出一次就好了。 最后,注意输出样例中给出的数据范围,保证输入的参数都在合法范围内才能进行计算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值