HDU5407——最小公倍数+逆元求法——CRB and Candies

逆元 inv

应用于取模运算中

加法 (a + b) % p = a % p + b % p;

减法 (a - b)  % p = a % p  - b % p;

乘法 (a * b)  % p = a % p * b % p;

但是除法

(a / b) % p : 

a * b % p = c;

已知 b, c, p 求 a

a = c * d % p

c就是b的逆元

一个数逆元求法

推导过程

第二种求法(推荐)

用快速幂o(log(b)

代码实现

ll pow_mod(ll a, ll b, ll p){
    ll ret = 1%p;
    while(b){
        if(b&1) ret = ret * 1ll * a % p;
        a = a * 1ll * a % p;
        b >>= 1;
    }
    return ret;
}

好了现在知道了逆元求法,说题目

打表发现有一个规律,n的排列组合的lcm就是(1到n+1)的lcm/(n+1) % mod

知道了逆元求法,n+1解决了,那么1-n+1的lcm怎么求?

官方题解

因为p的1次2次3次这些数都是只有一个的2,4,8,16这种,一旦出现n =pow(p,k)那么说明要乘上一个最小质因子

/************************************************
* Author        :Powatr
* Created Time  :2015-8-21 14:10:33
* File Name     :1002.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int MAXN = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;

ll prim[MAXN];
ll f[MAXN];
bool ok(ll x)
{
    ll y = prim[x];
    while(x%y == 0 && x > 1) x/=y;
    if(x == 1) return true;
    return false;
}

void inti()
{
    for(int i = 1; i <= MAXN; i++) 
        prim[i] = i;
    for(int i = 2; i <= MAXN; i++){
        if(prim[i] == i){
            for(int j = i + i; j <= MAXN; j += i){
                prim[j] = i;
            }
        }
    }
    f[0] = 1;
    for(int i = 1; i <= MAXN; i++){
        if(ok(i)) f[i] = f[i-1] * prim[i] % mod;
        else f[i] = f[i-1];
    }
}

ll pow_mod(ll a, ll b, ll p){
    ll ret = 1%p;
    while(b){
        if(b&1) ret = ret * 1ll * a % p;
        a = a * 1ll * a % p;
        b >>= 1;
    }
    return ret;
}

ll inv(ll a, ll b){
    return pow_mod(a, b-2, b);
}

int  main(){
    //Eular();
    inti();
    int T, n;
    for(scanf("%d", &T); T--; ){
        scanf("%d", &n);
        n++;
    ll ans = f[n] * inv(n, mod) % mod;
    printf("%I64d\n", ans);
    }
    return 0;
}

  

posted @ 2015-08-21 14:58  Painting、时光  阅读(325)  评论(0编辑  收藏  举报