洛谷 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;
}
上一篇:快乐的一天从AC开始 | 20210627 | CF1541B


下一篇:HDU 6755 - Fibonacci Sum(二项式定理+推式子)