洛谷 P1445 [Violet]樱花

原文地址

分析

题目要求求出不定方程:\(\dfrac{1}{x} + \dfrac{1}{y} = \dfrac{1}{n}\)的解\((x,y为未知数,n为给定的常数)\)

观察原式可以发现\(x\)\(y\)必定大于\(n!\),那么不妨令

                   \(y=n!+k,(k\in Z^*)\)

则原式变为

                   \(\dfrac{1}{x}+ \dfrac{1}{n!+k}= \dfrac{1}{n!}\)

变形之后得到

                   \(x=\dfrac{n!*(n!+k)}{k}\)

进一步得到

                   \(x=\dfrac{(n!)^2}{k}+n!\)

分析到这里我们就将其转化为\(x\)关于\(k\)的一个方程,而我们要求得数对\((x,y)\)的个数也就是方程解的个数。

因为\(x\)是正整数,所以\(\dfrac{(n!)^2}{k}+k\)也为正整数。

由于\(k\in Z^{ * }\),所以\((n!)^2\)必须能够被\(k\)整除,换句话说就是\(k\)\((n!)^2\)的约数。

所以这道题的实质是:
                   \(求n!^2的所有正约数的个数\)

约数个数

根据算数基本定理得正整数\(N\)能被唯一分解为
                   \(N=p_{1}^{c_1}*p_{2}^{c_2}*p_{3}^{c_3}*\cdots*p_{n}^{c_n}\)

其中\(c\)为任意常数,\(p\)为质数,且满足\(p_1\leq p_2\leq p_3\leq\cdots p_n\)

\(N\)的正约数个数为
                   \((c_1+1)*(c_2+1)*(c_3+1)\cdots*(c_n+1)= \prod_{i=1}^n (c_i+1)\)

为了提高效率,我们采用线性筛素数的方法,先找出\(n!\)的质因子,再通过分解质因数的方法找出所有的\(c_i\)即可。

注意我们这里只是找出了\(n!\)的所有的\(c_i\),而题目要求的是\((n!)^2\)的约数个数,所以统计时一定要乘\(2\)

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1000010, mod = 1e9 + 7;

int primes[N], cnt;
int sum[N];
bool st[N];
int n;

void init(int n) 
{
    for (int i = 2; i <= n; i ++ ) 
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ ) 
        {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

int main() 
{
    cin >> n;
    init(n);
    
    for (int i = 0; i < cnt; i ++ ) 
        for (LL j = primes[i]; j <= n; j *= primes[i]) 
            sum[i] += n / j;
    
    LL res = 1;
    for (int i = 0; i < cnt; i ++ ) 
        res = res * (2 * sum[i] + 1) % mod;
        
    cout << res << endl;
    
    return 0;
}
posted @ 2021-05-10 01:57  筱翼深凉  阅读(56)  评论(0编辑  收藏  举报