zoukankan      html  css  js  c++  java
  • OwenOwl's test D1T2无聊

    ## $Description$:

    薇奈把珈百璃的电脑收走了,无聊的珈百璃只好躺在床上数数。

    珈百璃想:一个数有很多很多约数,这些约数又有很多很多约数,那一个数就有很多约数的约数。

    珈百璃想:12 有多少个 **约数的约数** 呢?12 的约数有1 , 2 , 3 , 4 , 6 , 12 ,这些数分别有1 , 2 , 2 , 3 , 4 , 6 个约数,那12 有18 个约数的约数。

    珈百璃想:1 ~ $n$ 的数里哪个数的约数的约数个数最多呢?
    没了电脑的珈百璃数不出来(虽然她一有电脑就会打网游),于是她请求你帮忙。

    ## $Input$:


    一个整数$n$。
    ## $Output$:


    输出共两行。

    第一行一个正整数表示约数的约数个数最多的数,如果有多个输出最小的。

    第二行一个正整数表示这个数的约数的约数的个数。
    ## $Sample$ $I$:


    ### $Input$:


    15
    ### $Output$:


    12

    18
    ## $Sample$ $II$:


    ### $Input$:


    114514
    ### $Output$:


    110880

    3402
    ## $Constraint$:


    | 测试点 |范围 |
    | :----------:|:----------: |
    | $1$ |$n<=10$ |
    | $2$ |$n<=10^3$ |
    | $3$ |$n<=10^5$ |
    | $4$ |$n<=10^7$ |
    | $5$ |$n<=10^9$ |
    | $6,7$ |$n<=10^{13}$ |
    | $8,9,10$| $n<=10^{18} $ |

    ## $Solution$ :


    蒟蒻的我在考试的时候看到这道题目,二话不说直接观察数据点,发现可以使用打表过至少前4个点,大致做法就是先预处理出$1$~$10^7$中每个数的约数的个数(枚举当前这个数的倍数去更新其以后的数的约数个数,去注意要加上1和它本身)。

    然后再用类似的原理更新其约数的约数和。复杂度是

    $O(n*(1+1/2+1/3+...+1/n))approx O(nlog_n)$

    打$10^7$的表还是很快的~~其实还可以骗70分,具体我不会可以找lwq大佬~~。

    下面是部分分解:
    ```
    //打表
    #include<bits/stdc++.h>
    using namespace std;
    long long f[10000001],dp[10000001];
    int main()
    {
    freopen("2.txt","w",stdout);
    int n=10000000;f[1]=1;
    for(register int i=2;i<=n;++i){
    f[i]+=2;
    for(register int j=2;j*i<=n;++j)
    f[j*i]++;
    }
    dp[1]=1;
    for(register int i=2;i<=n;++i){
    dp[i]+=1;
    for(register int j=1;i*j<=n;++j)
    dp[i*j]+=f[i];
    // printf("%d %lld ",i,dp[i]);
    }
    int s=1;
    dp[n+1]=2e15;
    for(register int i=2;i<=n+1;++i){
    if(dp[i]>dp[i-1]){
    printf("{%d,%d,%lld}, ",s,i-1,dp[i-1]);
    s=i;
    }
    dp[i]=max(dp[i],dp[i-1]);
    }
    }
    ```
    ```
    #include<bits/stdc++.h>
    using namespace std;
    int ans[70][3]={/*打的表*/};
    int main()
    {
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    int n;
    scanf("%d",&n);
    for(register int i=0;i<=66;++i){
    if(n<=ans[i][1]){
    printf("%d %d",ans[i][0],ans[i][2]);
    return 0;
    }
    }
    }
    ```
    ## 正解 :


    根据“唯一分解定理”可以得到对于一个数$n$,可以将其分解为

    $p_1^{r1}p_2^{r2}....p_k^{rk}$

    那么其约数的个数就可以表示为

    $(r_1+1)(r_2+1)....(r_k+1)$

    (很容易用乘法定理推出)

    而我们也可以用乘法定理推出对于其任意约数

    $p_1^{r1'}p_2^{r2'}...
    p_k^{rk'}$,$r_i'in[0,r_i]$

    显然我们不能枚举每一个$n$的约数来计算它们的约数个数,但是根据乘法分配律和结合律我们可以发现对于一个数

    $ans_x= (1+2+...+(r_1 +1)) (1+2+...+(r_2 +1))...(1+2+...+(r_k +1))$

    这里是难点,仔细想一想为什么这样可以表示出所有情况。。

    那么其实问题基本上已经迎刃而解了,唯一要解决的就是如何才能找到1~n中符合条件的最小的数,我们发现 $prod_{i=1}^{cntpri}pri[i]$
    在当$pri[i]=53$时已经大于$10^{18}$,而如果我们考虑把$53$前的一个质数换为大于$53$的质数时,对$ans_x$的贡献一定是前者更大,因为有$r_i geq r_j$。

    所以一定有

    $(1+2+...+(r_i +1))geq(1+2+...(r_j+1))$。

    考虑 $dfs$ 时,我们最多只用dfs到$53$就一定可以求出答案了。此处要注意一个强力剪枝,就是记录前一个选择的质数的次数,后面选的质数的指数一定不能大于前一个,因为如果后一个系数比前一个大,那么在最好的情况下也是和之前的 $ans$ 相同,而题目让我们使求得的数字最小,所以后者一定与$ans$无关。也许你要问为什么不全选2呢。举个简单但是不严谨的例子,假如我们枚举了$2^7$和$2^6 imes3$则最终的答案分别是 $28$ 与 $21 imes3$ ,所以是有可能对$ans_x$有贡献的。

    ## $Codeing$ :


    ```
    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ll;
    int pri[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
    ll ans,ans2,n;

    inline void dfs(int pos,ll now,ll sum,int pre){
    if(sum>ans){
    ans=sum;ans2=now;
    }else if(sum==ans)
    ans2=(ans2<now)?ans2:now;
    for(register int i=1;i<=pre&&(long double)now*pri[pos]<=n;++i){
    now*=pri[pos];
    dfs(pos+1,now,sum*(i+1)*(i+2)/2,i);
    }
    }

    int main()
    {
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    scanf("%lld",&n);
    dfs(0,1,1,100);
    printf("%lld %lld",ans2,ans);
    }
    ```

  • 相关阅读:
    js之判断非空
    解决eclipse添加不了tomcat8的问题
    Java(eclipse)连接MySQL8.0以上版本数据库方式
    面试必备的:Redis和MongoDB的区别
    简述关系型数据库和非关系型数据库
    非关系型数据库MongoDB初探,以及和Redis的对比
    day53:django:URL别名/反向解析&URL分发&命名空间&ORM多表操作修改/查询
    day52:django:ORM单表/多表操作
    day51:django:dispatch&模板渲染&过滤器&标签&组件&静态文件配置
    day50:django:有名/无名分组&FBV/CBV
  • 原文地址:https://www.cnblogs.com/Pluto-Xz/p/11267618.html
Copyright © 2011-2022 走看看