题意:
给定 1 ≤ N ≤ 1 e 6 1 \le N \le 1e6 1≤N≤1e6 , 求满足 1 x + 1 y = 1 N ! \frac{1}{x} + \frac{1}{y} = \frac{1}{N!} x1+y1=N!1 的正整数有序对 ( x , y ) (x, y) (x,y) 的数量(模1e9+7)。
分析:
根据小学数学,变形式子:
N
!
(
x
+
y
)
=
x
y
N!(x + y) = xy
N!(x+y)=xy
同时出现了
x
+
y
x + y
x+y 项和
x
y
xy
xy 项,设法消去其中某一项。
构造:
(
x
−
N
!
)
(
y
−
N
!
)
=
x
y
−
N
!
(
x
+
y
)
+
(
N
!
)
2
(x - N!)(y-N!) = xy -N!(x + y) + (N!)^2
(x−N!)(y−N!)=xy−N!(x+y)+(N!)2
得出
(
x
−
N
!
)
(
y
−
N
!
)
=
(
N
!
)
2
(x - N!)(y-N!) = (N!)^2
(x−N!)(y−N!)=(N!)2
设
a
=
x
−
N
!
,
b
=
y
−
N
!
a = x - N!, b = y - N!
a=x−N!,b=y−N!,则转化为求有多少正整数有序对
(
a
,
b
)
(a, b)
(a,b) 满足
a
b
=
(
N
!
)
2
ab = (N!)^2
ab=(N!)2。(证明:
a
,
b
a, b
a,b 一定是正的。一个有趣的方法是类比电阻并联,题目中的式子可以理解为阻值为
x
x
x 的电阻与阻值为
y
y
y 的电阻并联,得到阻值为
N
!
N!
N! 的总阻值。根据初中物理的结论,并联电阻总阻值小于任何一个支路的阻值,所以
x
,
y
>
N
!
x, y \gt N!
x,y>N!, 即
a
,
b
>
0
a, b \gt 0
a,b>0。)
欧拉筛预处理 N ! N! N! 的质因子集合 P P P,统计每个 p i p_i pi 的贡献。得到唯一分解式 N ! = ∏ p i c i N! = \prod p_i^{c_i} N!=∏pici,则 ( N ! ) 2 = ∏ p i 2 c i (N!)^2 = \prod p_i^{2c_i} (N!)2=∏pi2ci。
若考虑无序对 ( u , v ) (u, v) (u,v), 对于每个质因子 p i p_i pi, u u u 可选 [ 0 , 2 c i ] [0, 2c_i] [0,2ci] 种幂次,则 v v v 的幂次与 u u u 加起来为 2 c i 2c_i 2ci,所以一个质因子 p i p_i pi 有 2 c i + 1 2c_i + 1 2ci+1 种选法。一共有 ∏ ( 2 c i + 1 ) \prod (2c_i + 1) ∏(2ci+1) 个无序对,其中有一对有 u = v u = v u=v。所以有序对为 ∏ ( 2 c i + 1 ) − 1 2 + 1 \frac{\prod (2c_i + 1) - 1}{2} + 1 2∏(2ci+1)−1+1 对。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N_MAX = 1e6 + 10;
const long long mod = 1e9 + 7;
long long pf[N_MAX];
inline long long power(long long a, long long k = mod - 2) {
a %= mod;
long long ans = 1;
while (k) {
if (k & 1) ans = ans * a % mod;
a = a * a % mod;
k >>= 1;
}
return ans;
}
vector<int> prime;
int d[N_MAX];
long long N;
int main() {
cin >> N;
for (int i = 2; i <= N; i++) {
if (!d[i]) {
d[i] = i;
prime.push_back(i);
}
for (int j = 0; j < prime.size(); j++) {
if (prime[j] * i > N || prime[j] > d[i]) break;
d[prime[j] * i] = prime[j];
}
}
for (auto it : prime) {
long long dd = 1;
for (int i = 1; (dd *= it) <= N; i++) {
pf[it] += (N / dd);
}
// printf("%d: %lld\n", it, pf[it]);
}
long long ans = 1;
for (int i = 0; i < prime.size() ; i++) ans = (ans * (2LL * pf[prime[i]] + 1))% mod;
ans++;
ans = ans * power(2) % mod;
printf("%lld\n", ans);
}