LCM为n的最小因子和

题目描述

LCM可以看成一组数的最小公倍数,即这些数公有的倍数。比如1 12的最小公倍数是12,3、4、5的最小公倍数为60。现如今给你一个正整数n,你必须发现一组数(这个组的大小必须大于1),使这一组数的LCM为n,同时使这一组数的和最小,并输出最小的和。比如如果给定n为12,1、12和3、4的LCM都为n,但是12+1>3+4所以最后的结果输出7。

输入描述

输入一个正整数n(2<=n<=10^9)

输出描述

按要求输出最小的和。

样例

输入

12

输出

7

话不多说,上代码:

#include<bits/stdc++.h>
using namespace std;
long long a[500000];
int main(){
    long long n,cnt=0,sum=0,x;
    cin>>n;
	for(long long i=2;i<=n;i++){
		if(n%i==0){
		    cnt++;
		    x=0;
			while(n%i==0){
			    x++;
				n/=i;
			}
			a[cnt]=pow(i,x);
		}
	}
	if(cnt==1){
	    cnt++;
	    a[cnt]=1;
	}
	for(long long i=1;i<=cnt;i++){
	    sum+=a[i];
	}
	cout<<sum;
	return 0;
}

首先,我们需要知道一个结论:一个的质因子目等于其所有质因子的指之和加1。比如,$24=2^3\times3$,其质因子目为$3+1=4$。 接下来,我们可以使用暴力枚举子组的方法,对每个子组求出其最小公倍数,然后计算其质因子目之和即可。时间复杂度为$O(n^3)$,其中$n$为组长度,由于子量为$O(n^2)$,对每个子组求最小公倍数的时间复杂度为$O(n)$。 代码如下: ```python def gcd(a, b): if b == 0: return a return gcd(b, a % b) def lcm(a, b): return a * b // gcd(a, b) def count_factors(num): count = 0 for i in range(2, int(num**0.5)+1): while num % i == 0: count += 1 num //= i if num > 1: count += 1 return count def subarray_lcm_factor_sum(arr): n = len(arr) ans = 0 for i in range(n): for j in range(i, n): subarr_lcm = arr[i] for k in range(i+1, j+1): subarr_lcm = lcm(subarr_lcm, arr[k]) ans += count_factors(subarr_lcm) return ans ``` 然而,上述方法的时间复杂度较高,不能通过本题。考虑优化。 观察题目的据范围,发现组中每个元素都小于$10^6$,因此一个子组的最小公倍数也不可能超过$10^6$,这启示我们可以对每个质预处理出其在$[1,10^6]$范围内的倍数中出现的次。具体地,我们可以使用线性筛法预处理出所有小于等于$10^6$的质,然后对每个质$p$,预处理出其在$[1,10^6]$范围内的倍数中出现的次$cnt_p$,即: $$cnt_p=\sum_{i=1}^{\lfloor 10^6/p\rfloor}\lfloor\frac{i}{p}\rfloor$$ 这里的$\lfloor x\rfloor$表示不超过$x$的最大整。例如,当$p=2$时,有$cnt_2=\lfloor 10^6/2\rfloor+\lfloor 10^6/4\rfloor+\lfloor 10^6/8\rfloor+\cdots=500000+250000+125000+\cdots$。这个式子可以用等比列求和公式简化为$cnt_2=10^6-1$。 预处理完成后,对于每个子组,我们可以依次枚举$[1,10^6]$范围内的质$p$,统计其在子组的最小公倍数中出现的次。具体地,设当前枚举到的质为$p$,统计$p^{cnt_p}$在子组的最小公倍数中出现的次。这个量等于子组中所有元素中$p$的指最小值乘以$cnt_p$。 具体地,我们可以用一个长度为$10^6+1$的组$factor$来存储每个对应的最小因子。我们可以先用线性筛法求出所有小于等于$10^6$的质,并将它们的倍数都标记上最小因子。然后,对于每个子组,我们可以使用一个长度为$10^6+1$的组$cnt$来统计每个质的指之和,然后根据上述公式计算质因子目之和。 总时间复杂度为$O(n\log\log 10^6)$,其中$n$为组长度。 代码如下: ```python def subarray_lcm_factor_sum(arr): n = len(arr) # 预处理每个最小因子 factor = [0] * (10**6+1) primes = [] for i in range(2, 10**6+1): if factor[i] == 0: factor[i] = i primes.append(i) for p in primes: if p > factor[i] or i*p > 10**6: break factor[i*p] = p # 预处理每个质在[1,10^6]范围内的倍数中出现的次 cnt = [0] * (10**6+1) for p in primes: cnt[p] = 10**6 // p for i in range(2, cnt[p]+1): cnt[p] -= cnt[i*p] # 枚举子组,统计质因子目之和 ans = 0 for i in range(n): for j in range(i, n): subarr_lcm = arr[i] for k in range(i+1, j+1): subarr_lcm = lcm(subarr_lcm, arr[k]) for p in primes: if p > subarr_lcm: break exp_sum = float('inf') for x in arr[i:j+1]: exp_sum = min(exp_sum, get_exponent(x, p)) ans += exp_sum * cnt[p] return ans ``` 其中,$get\_exponent(x,p)$用于计算$x$在质因分解中$p$的指,代码如下: ```python def get_exponent(num, prime): exp = 0 while num % prime == 0: exp += 1 num //= prime return exp ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值