题目链接: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;
}