Acwing1294_思维+质数

题目链接:https://www.acwing.com/problem/content/description/1296/

题目大意:
1 / x + 1 / y = 1 / n!; 求(x, y)的数量:

解题过程:
题面非常的简洁,所以刚开始拿到这道题没什么思路;然后只好进行通分化简;最终得到一个算式:y = 1 + (n!)^2 / (x - n!);
所以,将问题转化为了(n!)有多少个约数。
由于范围太大,所以直接的根号n的算法肯定是不行的;然后另一种方法是通过分解n!的质数然后得到n!的约数的个数,但是这样也会超时,因为可能的质数有70000多个;
所以,这里用到了一种思想,当要去计算一个数有多少个约数的时候,我们可以去计算这个约数被使用了多少次;前者的时间复杂度非常高而后者的时间复杂度则优化了一个log的级别。
但是,这里也需要注意,由于我们需要累加的是质数的个数,所以我们要不断的判断一个质数的一次方,二次方,直到大于n为止。

代码一份:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int maxn = 1e6 + 5, mod = 1e9 + 7;

int cnt;
int prime[maxn], sum[maxn];
bool vis[maxn];

inline void get_primes(int n) {
	for(int i = 2; i <= n; i ++) {
		if(!vis[i]) prime[cnt ++] = i;
		for(int j = 0; prime[j] * i <= n; j ++) {
			vis[i * prime[j]] = true;
			if(i % prime[j] == 0) break;
		}
	}
}

int main(void) {
//	freopen("in.txt", "r", stdin);
	int n; 
	scanf("%d", &n);
	get_primes(n);
	
	for(int i = 0; i < cnt; i ++) {
		
		for(LL j = prime[i]; j <= n; j *= prime[i]) {
			LL tmp = j;
			while(tmp <= n) {
				sum[i] ++;
				tmp += j;
			}
		}
	}
	
	for(int i = 0; i < cnt; i ++)
		sum[i] = sum[i] * 2 + 1;
		
	LL fi = 1;
	for(int i = 0; i < cnt; i ++)
		fi = (fi * sum[i]) % mod;
	
	printf("%lld\n", fi);
	
	return 0;
}
发布了179 篇原创文章 · 获赞 1 · 访问量 7584

猜你喜欢

转载自blog.csdn.net/weixin_42596275/article/details/104332841