• ACM学习历程—HDU5407 CRB and Candies(数论)


    Problem Description

    CRB has N different candies. He is going to eat K candies.
    He wonders how many combinations he can select.
    Can you answer his question for all K (0 ≤ K ≤ N )?
    CRB is too hungry to check all of your answers one by one, so he only asks least common multiple(LCM) of all answers.

    Input

    There are multiple test cases. The first line of input contains an integer T , indicating the number of test cases. For each test case there is one line containing a single integer N .
    1 ≤ T ≤ 300
    1 ≤ N ≤ 106 

    Output

    For each test case, output a single integer – LCM modulo 1000000007(109+7 ).

    Sample Input

    5

    Sample Output

    12 

    10

    题目要求的是所有C(n, i) (0 <= i <= n)的最小公倍数。

    这题如果直接用LCM去求会T掉,

    就算离线所有n!的逆元复杂度是O(n)

    然后for循环C(n, i)O(n)

    然后用LCM求最小公倍数是O(log(a)),最差情况接近O(log(10^9+7)) ~ 30

    所以复杂度最差是O(30n), 300组数据,最终需要O(10^10)左右。

    那个30不乘的话O(3*10^8)左右。卡了一个常数倍数量级。

    max(Vp(C(n, i))) = max(Vp(i+1)) - Vp(n+1) (0 <= i <= n)

    有了这个式子,就证明了[C(n, 0), C(n, 1) ,.....C(n, n)] = [1, 2, ....,n+1]/(n+1)

    等式两侧的质因子指数相等,自然等式就相等了。

    然后最终结果是所有p^maxN/p^k的乘积(其中maxN是pn+1内的最高次数,k是p能整除n+1的最高次数)

    也就是所有p^maxN的乘积除以p^k的乘积,分子等于[1, 2, 3,....n+1],分母等于n+1

    这个结果和题解的结论是一致的。

    证明过程有点搓。。。。

    如果顺序找到kmaxN的话,复杂度是O(num*log(p)),其中num是素数个数,p是素数。

    如果二分查找的话,是O(num*log(logp))

     

    此外托人找了另一种证明方式,很巧妙:

     

    代码:O(num*log(p))

     

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <algorithm>
    #define LL long long
    
    using namespace std;
    
    const LL MOD = 1e9+7;
    const int maxN = 1e6+5;
    bool isprim[maxN];
    int n, prim[maxN], top;
    
    //埃氏筛法求素数
    void isPrim()
    {
        memset(isprim, true, sizeof(isprim));
        isprim[0] = isprim[1] = false;//初始化
        for (LL i = 2; i < maxN; ++i)//筛法
        {
            if (isprim[i])
            {
                for (LL j = i*i; j < maxN; j += i)//上界太大可能会爆int
                {
                    isprim[j] = false;
                }
            }
        }
    }
    
    void init()
    {
        isPrim();
        top = 0;
        for (int i = 2; i < maxN; ++i)
            if (isprim[i])
                prim[top++] = i;
    }
    
    void work()
    {
        LL ans = 1;
        for (int i = 0; i < top && prim[i] <= n+1; ++i)
        {
            for (LL v = prim[i]; v <= n+1; v *= prim[i])
            {
                if ((n+1)%v)
                    ans = (ans*prim[i])%MOD;
            }
        }
        printf("%I64d
    ", ans);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        init();
        int T;
        scanf("%d", &T);
        for (int times = 0; times < T; ++times)
        {
            scanf("%d", &n);
            work();
        }
        return 0;
    }

     

     

  • 相关阅读:
    fetch API 和 ajax
    java 通过数据库名获得 该数据所有的表名以及字段名、字段类型
    自定义注解,通过反射获得注解中的值(详细自定义注解解释)
    main方法中sleep
    eclipse中设置JVM内存
    命令java 找不到或无法加载主类
    windows下的命令
    mac terminal基本命令
    ThreadLocal 源码剖析
    SQL中的函数用法
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4756707.html
Copyright © 2020-2023  润新知