bzoj1951

CRT+LUCAS+费马小定理+拓展欧拉定理

幂指数太大了怎么办?欧拉定理,n太大了怎么办?上lucas,模数太大了怎么办?上crt。然后就好了,唯一注意的是要用拓展欧拉定理,n%phi(p)+phi(p)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const ll mod = 999911659ll, t[4] = {2, 3, 4679, 35617};
ll n, g;
ll a[5], fac[4][40010];
ll power(ll x, ll t, ll mod)
{
    ll ret = 1ll;
    for(; t; t >>= 1ll, x = x * x % mod) if(t & 1ll) ret = ret * x % mod;
    return ret;
}
ll inv(ll x, ll p)
{
    return power(x, p - 2, p);
}
ll C(ll n, ll m, int id)
{
    if(n < m) return 0;
    ll ret = fac[id][n] % t[id] * inv(fac[id][m], t[id]) % t[id] * inv(fac[id][n - m], t[id]) % t[id]; 
//  printf("C(%lld %lld) = %lld mod = %lld\n", n, m, ret, t[id]);
    return ret;
}
ll lucas(ll n, ll m, int id)
{
    if(n < m) return 0;
    if(n < t[id] && m < t[id]) return C(n, m, id);
    return lucas(n % t[id], m % t[id], id) % t[id] * lucas(n / t[id], m / t[id], id) % t[id];
}
ll CRT()
{
    ll M = mod - 1, ret = 0;
    for(int i = 0; i < 4; ++i) ret = (ret + a[i] * (M / t[i]) % M * inv(M / t[i], t[i]) % M) % M;
    return ret % M;
}
int main()
{
    scanf("%lld%lld", &n, &g);
    for(int i = 0; i < 4; ++ i)
    {
        fac[i][0] = 1ll;
        for(int j = 1; j <= t[i]; ++j) fac[i][j] = fac[i][j - 1] * (ll)j % t[i];
        for(ll j = 1ll; j * j <= n; ++j) if(n % j == 0)
        {
            ll mul = lucas(n, j, i);
//          printf("C(%lld %lld) = %lld\n", n, j, mul);
            a[i] = (a[i] + mul) % t[i];
            if(j * j != n) 
            {
                mul = lucas(n, n / j, i);
//              printf("C(%lld %lld) = %lld\n", n, n / j, mul);
                a[i] = (a[i] + mul) % t[i];
            }
        }
    }
    printf("%lld\n", power(g % mod, CRT() % (mod - 1) + mod - 1, mod) % mod);
    return 0;
}
View Code

 

posted @ 2017-09-05 21:15  19992147  阅读(126)  评论(0编辑  收藏  举报