【数论】[因数个数]P4167樱花

题目描述

求不定方程 \(\frac {1}{x} + \frac{1}{y} = \frac{1}{n!}\)的正整数解的个数

\(n \leq 100^6\)

Solution

化简得

\(x * n! + y * n! = x * y\)

\(x * y - x * n! - y *n! +(n!)^2 = (n!)^2\)

\((x - n!)(y - n!) = (n!)^2\)

以上,我们可以看出,所求正整数解的个数其实就是\((n!)^2\)的约数的个数。

这个当然可以暴力求,但是很慢。考虑一个质数p在n!中出现的次数,显然是\(\frac{n}{p}\),这既表示n中包含几个p,同时也能说明小于等于n的数中,有多少个是p的倍数。同理\(p^2\)在n!中出现的次数是\(\frac{n}{p^2}\),以此类推,最后将这些全部加起来就是p在n!阶乘中出现的次数。在应用因子个数公式即可。

for(int i = 1; pri[i] <= n; ++i){
    int tot = 0, x = n, y = pri[i];
    while(x) tot += x / y, x /= y;
    ans = (ans * (tot << 1 | 1) % mod) % mod;//之所以要<<1是因为是n!*n!
  }

举个例子或许好理解。

13!中有多少个3?包含3这个因数的数有:3, 6, 9, 12,分别包含1, 1, 2, 1个3,总数就是5个。而13 / 3 = 4, 4 / 3 = 1, 4 + 1 = 5。

Code

#include <iostream>
#include <cstdio>
using namespace std;
inline long long read() {
  long long x = 0; int f = 0; char c = getchar();
  while (c < '0' || c > '9') f |= c == '-', c = getchar();
  while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
  return f? -x:x;
}

const int mod = 1e9 + 7;
int n, pri[1000006], cnt;
long long ans = 1;
bool v[1000006];
inline void get_pri() {
  for (int i = 2; i <= 1000000; ++i) {
    if (!v[i]) pri[++cnt] = i;
    for (int j = 1; j <= cnt && pri[j] * i <= n; ++j) {
      v[pri[j] * i] = 1;
      if (i % pri[j] == 0) break;
    }
  }
}
int main() {
  n = read();
  get_pri();
  for (int i = 1; pri[i] <= n; ++i) {
    int tot = 0, x = n, y = pri[i];
    while (x) tot += x / y, x /= y;
    ans = (ans * (tot << 1 | 1) % mod) % mod;
  }
  printf("%lld\n", ans);
  return 0;
}
posted @ 2019-10-08 16:31  Kylin_Seven  阅读(210)  评论(0编辑  收藏  举报