[51nod-1189] 阶乘分数

题意:

给定 1 ≤ N ≤ 1 e 6 1 \le N \le 1e6 1N1e6 , 求满足 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 (xN!)(yN!)=xyN!(x+y)+(N!)2
得出 ( x − N ! ) ( y − N ! ) = ( N ! ) 2 (x - N!)(y-N!) = (N!)^2 (xN!)(yN!)=(N!)2
a = x − N ! , b = y − N ! a = x - N!, b = y - N! a=xN!,b=yN!,则转化为求有多少正整数有序对 ( 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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值