• 洛谷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!) imes (x+y) ]

    一个骚操作,两边同时加上((n!)^2),为什么,因为方便因式分解...

    [(n!)^2-(n!) imes (x+y)+xy=(n!)^2 ]

    然后因式分解

    [(n!-x) imes (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} imes p_2^{c_2} imes ... imes p_m^{c_m} ]

    [(n!)^2=p_1^{2 imes c_1} imes p_2^{2 imes c_2} imes ... imes p_m^{2 imes c_m} ]

    由于每个质因子(p_i)都有(2 imes c_i+1)种取值,所以

    [ans=(2 imes c_1+1) imes (2 imes c_2 +1) imes ... imes(2 imes c_m+1) ]

    那么最后问题就转化成了对(n!)进行分解质因数,并求质因数的个数

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

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

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

    [lfloorfrac{n}{p} floor+lfloorfrac{n}{p^2} floor+...+lfloorfrac{n}{p^{log_{p}{n}}} floor ]

    对于每个质因子,我们只需要(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;
    }
    
  • 相关阅读:
    在CentOS中安装VMware Tools
    引用
    iomanip头文件库函数
    第2章 寄存器(CPU工作原理)
    二维差分
    组合数学——康托展开和逆康托展开
    动态规划精讲(一)区域和检索
    动态规划精讲(一)最大子矩阵
    freopen
    动态规划精讲(一)环形子组数的最大和
  • 原文地址:https://www.cnblogs.com/real-l/p/9839175.html
Copyright © 2020-2023  润新知