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; }