1 条题解

  • 0
    @ 2026-10-26 3:53:48

    思路与算法

    记 N=n!N=n!。原式通分得到 xy=N(x+y)xy=N(x+y),移项为

    (x−N)(y−N)=N2.(x-N)(y-N)=N^2.

    因为 x,yx,y 都为正且原式成立,必有 x>N,y>Nx>N,y>N。于是对 N2N^2 的每个正因数 dd,令 x=N+d, y=N+N2/dx=N+d,\ y=N+N^2/d,恰得一组正整数解。题目计有序对,不能再除以2。

    若 N=∏pepN=\prod p^{e_p},则 N2N^2 的约数个数为 ∏(2ep+1)\prod(2e_p+1)。无需构造巨大阶乘。用埃氏筛枚举 p≤np\le n,通过

    $$e_p=\lfloor n/p\rfloor+\lfloor n/p^2\rfloor+\cdots$$

    计算它在 n!n! 中的指数。程序从 v=nv=n 开始反复整除 pp 并累加,避免显式连乘 pkp^k。最后把各项乘积对 109+710^9+7 取模。n=1n=1 时质因子表为空,空积为1,对应解 (2,2)(2,2)。

    正确性说明

    通分和配方对正数等价。由 1/x<1/N1/x<1/N 可知 x>Nx>N,同理 y>Ny>N,所以两个移位量均为正。映射 d=x−Nd=x-N 把原式的每个有序解对应到 N2N^2 的一个正因数;反向构造也是正整数解,且互为逆映射,因此解数正是因数个数。

    一个素数 pp 的倍数对阶乘提供一次 pp,p2p^2 的倍数再提供一次,依此类推,逐层计数恰得指数公式。唯一分解保证平方后每个素数指数为 2ep2e_p,每个因数独立选取指数0至 2ep2e_p,共有 ∏(2ep+1)\prod(2e_p+1) 种。逐步取模保持乘积余数,所以输出为所求解数模数值。

    复杂度

    初始化筛数组为 O(n)O(n),埃氏筛为 O(nlog⁡log⁡n)O(n\log\log n)(小规模可写 O(nlog⁡log⁡(n+2))O(n\log\log(n+2)))。指数累加精确需 O(∑p≤n(1+⌊log⁡pn⌋))O(\sum_{p\le n}(1+\lfloor\log_p n\rfloor)),给出简单总上界 O(nlog⁡log⁡(n+2)+π(n)log⁡(n+1))O(n\log\log(n+2)+\pi(n)\log(n+1))。筛数组占 O(n)O(n),其余仅常数变量,总额外空间 O(n)O(n)。不生成 n!n! 或所有解。

    易错点

    1. (x,y)(x,y) 有顺序,样例的 (3,6)(3,6) 与 (6,3)(6,3) 都计入。
    2. 求的是阶乘平方的因数个数,所以使用 2ep+12e_p+1,不是 ep+1e_p+1。
    3. 用反复整除求指数,不显式算巨大阶乘或不断乘素数幂。
    4. 每次模乘前用64位;本范围指数不超过 nn,因子与模内结果之积小于64位上界。
    5. 覆盖 n=1n=1、小质数、最大值及接近上界的质数。独立答案按2至n逐个分解累加,未把参考程序同一指数循环当独立验证。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        vector<bool> bad(n + 1);
        ll result = 1;
        for (int p = 2; p <= n; p++)
            if (!bad[p]) {
                if (p <= n / p)
                    for (int k = p * p; k <= n; k += p)
                        bad[k] = true;
                ll exponent = 0;
                for (int v = n; v;) {
                    v /= p;
                    exponent += v;
                }
                result = result * (2 * exponent + 1) % 1000000007;
            }
        cout << result << '\n';
    }
    
    • 1

    信息

    ID
    1655
    时间
    1000ms
    内存
    512MiB
    难度
    普及
    标签
    递交数
    1
    已通过
    1
    上传者