HDU 5407 费马小定理

HDU 5407

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5407

题意:

,求g(n)

思路:

首先有一个公式,设,,则。公式证明很复杂也没看懂也不想看,好像都是上数列网和打表找规律过的。

那么现在我们有f(n+1)了,要求f(n+1)/(n+1) %(1e9+7),需要用费马小定理来求带模除法的逆元。

原理

m是素数且m不能整除bb,有b^(m - 1) = 1 mod (m)   证明可见扩展欧几里得

则 (a / b) % m

  = (a / b * b ^ (m - 1) ) % m

  = (a * b^(m - 2)) % m

完。

源码:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

using namespace std;

#define LL long long

#define MOD (1000000007)

const int MAXN = 1e6 + 5;

int prime[MAXN], vis[MAXN], val[MAXN];

LL LCM[MAXN];

void init()

{

    int cnt = 0;

    memset(vis, 0, sizeof(vis));

    for(int i = 2 ; i < MAXN ; i++){

        if(vis[i] == 0){

            prime[cnt++] = i;

            int now = i;

            while(now < MAXN){

                vis[now] = 1;

                now += i;

            }

        }

    }

    for(int i = 1 ; i < MAXN ; i++)

        val[i] = 1;

    for(int i = 0 ; i < cnt ; i++){

        LL temp = prime[i];

        while(temp < MAXN){

            val[temp] = prime[i];

            temp *= prime[i];

        }

    }

    LCM[1] = 1;

    for(int i = 2 ; i < MAXN ; i++)

        LCM[i] = (LCM[i - 1] * val[i]) % MOD;

}

LL ppow(LL a, int b, LL m)

{

    LL temp = 1;

    while(b){

        if(b & 1)

            temp = (temp * a) % m;

        a = (a * a) % m;

        b >>= 1;

    }

    return temp;

}

LL cal(int mark)

{

    LL temp = mark;

    temp = ppow(temp, MOD - 2, MOD);

//    printf("LCM = %I64d, temp = %I64d\n", LCM[mark], temp);

    LL ans = (LCM[mark] * temp) % (LL)MOD;

    return ans;

}

int main()

{

    init();

    int t;

    scanf("%d", &t);

    while(t--){

        int n;

        scanf("%d", &n);

        LL ans = cal(n + 1);

        printf("%I64d\n", ans % MOD);

    }

    return 0;

}

 

你可能感兴趣的:(HDU 5407 费马小定理)