HDU5407.CRB and Candies(数论)

官方题解:

The problem is just to calculate g(N) = LCM(C(N,0),C(N,1),...,C(N,N))

Introducing function f(n) = LCM(1,2,...,n), the fact g(n) = f(n+1)/(n+1) holds.

We calculate f(n) in the following way.

f(1)=1

If n =p^k,then f(n) = f(n−1)× p, else f(n) = f(n−1).

Time complexity:O(N⋅logN)

 

这题用学的知识:

1。乘法逆元

求(a/b)%c时 化成 (a%c)/(b%c)是错误的,所以需要用到乘法逆元。(a%c)*(b^-1%c)。

b^-1的求法:

费马小定理(Fermat Theory): 假如p是质数,且Gcd(a,p)=1,那么 a^(p-1)(mod p)≡1。

由此可得a*a^(p-2)=1 (mod p) 即a^(p-2)就是a的乘法逆元。通过快速幂可求。

2。LCM(C(N,0),C(N,1),...,C(N,N))=LCM(1,2,...,n)/(n+1)

知乎上看到有人证明,并没有看懂。http://www.zhihu.com/question/34859879

3。求LCM(1,2,...,n)的简便算法

If n =p^k,then f(n) = f(n−1)× p, else f(n) = f(n−1).

 

代码:

#include <iostream>
#include <cstdio>
#include <cstring>

typedef long long ll;

const int N = 1000002;
const ll MOD = 1000000007;

int v[N + 5];
ll f[N + 5];
int is_p[N + 5];
int p[N + 5];
int cnt_p;

int n;

void get_p()
{
    for (int i = 0; i <= N; ++i) is_p[i] = 1;
    cnt_p = 0;
    is_p[0] = is_p[1] = 0;
    for (int i = 2; i <= N; ++i) {
        if (is_p[i]) {
            p[cnt_p++] = i;
            for (int j = i * 2; j <= N; j += i)
                is_p[j] = 0;
        }
    }
}

ll pow(ll a, ll b)
{
    ll res = 1;
    while (b > 0) {
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

ll MIM(ll a)
{
    return pow(a, MOD-2);
}

void get_f()
{
    for (int i = 0; i < cnt_p; ++i) {
        ll j = 1;
        while (j < N) {
            v[j] = p[i];
            j *= p[i];
        }
    }
    f[1] = 1;
    for (int i = 2; i <= N; ++i) {
        if (v[i]) f[i] = f[i - 1] * v[i] % MOD;
        else f[i] = f[i - 1];
    }
}

int main()
{
    get_p();
    get_f();

    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        
        printf("%lld\n", f[n + 1] * MIM(n + 1) % MOD);
    }

    return 0;
}

  

posted @ 2015-08-22 14:10  我不吃饼干呀  阅读(287)  评论(0编辑  收藏  举报