洛谷P1445 [Violet] 樱花 (数学)

洛谷P1445 [Violet] 樱花

题目背景

我很愤怒

题目描述

求方程 1/X+1/Y=1/(N!) 的正整数解的组数,其中N≤10^6。

解的组数,应模1e9+7。

输入输出格式

输入格式:

输入一个整数N

输出格式:

输出答案

输入输出样例

输入样例#1:

1439

输出样例#1:

102426508

Solution

极其恶心的一道题...

看到这种题肯定是需要化简式子的,因为出题人不会好到给你一个好做的式子

\[\frac{1}{x}+\frac{1}{y}=\frac{1}{n!}\]
\[\frac{x+y}{xy}=\frac{1}{n!}\]
\[xy=(n!)\times (x+y)\]
一个骚操作,两边同时加上\((n!)^2\),为什么,因为方便因式分解...
\[(n!)^2-(n!)\times (x+y)+xy=(n!)^2\]
然后因式分解
\[(n!-x)\times (n!-y)=(n!)^2\]
\(a=(n!-x),b=(n!-y)\),因为\((n!)^2\)是确定的,所以确定了\(a\),就可以确定\(b\),也就可以确定\(x,y\)

那么a的方案数是多少?因为\(a\)\((n!)^2\)的因子,所以\(a\)的取值的方案数就是\((n!)^2\)的因子的方案数

然后根据唯一分解定理
\[n!=p_1^{c_1}+p_2^{c_2}+...+p_m^{c_m}\]
\[(n!)^2=p_1^{2\times c_1}+p_2^{2\times c_2}+...+p_m^{2\times c_m}\]
由于每个质因子\(p_i\)都有\(2\times c_i+1\)种取值,所以
\[ans=(2\times c_1+1)\times (2\times c_2 +1)\times ...\times(2\times c_m+1)\]
那么最后问题就转化成了对\(n!\)进行分解质因数,并求质因数的个数

暴力对\(1-n\)每个数分解质因数,再合并复杂度过高,为\(O(n\sqrt n)\)

由于\(n!\)的每个质因子都不超过n,所以我们可以预处理\(1-n\)内所有质数p,再考虑\(n!\)内一共有多少个质因子p

我们可以对于在线性筛质数的过程中同时处理一下n以内每个数的最小质因子\(p\),然后统计这个数的贡献,在\(1-n\)中至少包含一个质因子\(p\)的有\(\lfloor\frac{n}{p}\rfloor\),至少包含两个质因子p的有\(\lfloor\frac{n}{p^2}\rfloor\)...
那么\(n!\)中质因子\(p\)的个数就是
\[\lfloor\frac{n}{p}\rfloor+\lfloor\frac{n}{p^2}\rfloor+...+\lfloor\frac{n}{p^{log_{p}{n}}}\rfloor\]

对于每个质因子,我们只需要\(log\ n\)的时间来求解,所以总复杂度是\(O(n\ log\ n)\)

Code

#include<bits/stdc++.h>
#define rg register
#define il inline
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lol long long
#define in(i) (i=read())
using namespace std;

const lol N=1e6+10,mod=1e9+7;

lol read() {
    lol ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
    return ans*=f;
}

lol n,cnt,ans=1;
lol g[N],prime[N],c[N];

void init() {
    memset(g,0,sizeof(g));
    for(int i=2;i<=n;i++) {
        if(!g[i]) g[i]=i,prime[++cnt]=i;
        for(int j=1;j<=cnt && i*prime[j]<=n;j++) {
            g[i*prime[j]]=prime[j];
            if(i%prime[j]==0) break;
        }
    }
}

int main()
{ 
    in(n); init();
    for(int i=1;i<=n;i++)
        for(int j=i;j!=1;j/=g[j]) c[g[j]]++;
    for(int i=1;i<=n;i++) ans=ans*(c[i]*2+1)%mod;
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/real-l/p/9839175.html
今日推荐