bzoj2721 [Violet5]樱花

bzoj2721 [Violet 5]樱花

给出 \(n\)\(\frac{1}{x}+\frac{1}{y}=\frac{1}{n!}\) 的正整数解数量 \(\bmod (10^9+7)\)

\(n\leq10^6\)

数论


先化式子

\[\begin{aligned}&\frac{1}{x}+\frac{1}{y}=\frac{1}{n!}\\&\frac{xy}{x+y}=n!\\&xy=n!(x+y)\\&xy-n!x-n!y+n!^2=n!^2\\&(x-n!)(y-n!)=n!^2\end{aligned} \]

\(a=x-n!,\ b=y-n!\)

原题即为求 \(ab=n!^2\) 的整数解数量,即为 \(n!^2\) 的因数个数

\(n!=\displaystyle\prod_{p_i\in p}p_i^{c_i}\)

答案即为: $$\displaystyle\prod_{p_i\in p}{(2\times c_i+1)}$$

\(p.s.\ :\) 如果原题为本质不同的方案数,即 \(\verb|Luogu5253 丢番图|\) ,答案即为 \(\frac{ans+1}{2}\) 。因为对于每个 \(\{(a,\ b) | a\neq b\}\) 都被多算了一遍。

至于求出 \(c_i\) ,可以先筛出 \(1\cdots n\) 的每个质数 \(p\) ,然后考虑阶乘 \(n!\) 一共包含多少个 \(p\)

\(n!\)\(p\) 的个数等于 \(1\cdots n\) 中每个数包含 \(p\) 的个数之和。

\(1\cdots n\) 中, 至少包含一个 \(p\) 的数显然有 \(\lfloor\frac{n}{p}\rfloor\) 个。而至少包含两个 \(p\) 的数有 \(\lfloor\frac{n}{p^2}\rfloor\) 个。不过其中的一个质因子已经在 \(\lfloor\frac{n}{p}\rfloor\) 中统计过了,所以只需要再统计第二个质因子,即累加上 \(\lfloor\frac{n}{p^2}\rfloor\) ,而不是 \(2\times\lfloor\frac{n}{p^2}\rfloor\)\(\lfloor\frac{n}{p^3}\rfloor,\ \lfloor\frac{n}{p^4}\rfloor,\ \cdots\) 同理

综上所述, \(n!\) 中质因子 \(p\) 的个数为: $$\displaystyle\sum_{p^k\leq n}{\lfloor\frac{n}{p^k}\rfloor}$$

时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 10, P = 1e9 + 7;
int n, tot, p[maxn];

void sieve() {
  int tmp = sqrt(n) + 1;
  for (int i = 2; i <= tmp; i++) {
    for (int j = i * i; j <= n; j += i) {
      p[j] = 1;
    }
  }
  for (int i = 2; i <= n; i++) {
    if (!p[i]) p[++tot] = i;
  }
}

int main() {
  scanf("%d", &n);
  sieve();
  int ans = 1;
  for (int i = 1; i <= tot; i++) {
    int x = 1, s = 0;
    while (1ll * p[i] * x <= n) {
      x *= p[i], s += n / x;
    }
    ans = 1ll * ans * (s << 1 | 1) % P;
  }
  printf("%d", ans);
  return 0;
}
posted @ 2019-03-14 16:47  cnJuanzhang  阅读(168)  评论(0编辑  收藏  举报