Bzoj1951: [Sdoi2010]古代猪文
题面
Sol
超级数学板子题!!!
费马小定理,扩展欧几里德定理,中国剩余定理,卢卡斯定理等
题意就是求
\[G^{\sum_{k|N}C_N^k}\ mod\ 999911659
\]
首先根据扩展欧拉定理或者费马小定理
\(a^x\equiv a^{x\% (p-1)}(mod\ p)\)
\(p\)为质数
那么直接求那个
\(\sum_{k|N}C_N^k (mod\ 999911658)\)
就好了
模数不是质数\(lucas+CRT\)合并即可
然后\(CRT\)用上\(ExGcd\)
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
template <class Int>
IL void Input(RG Int &x){
RG int z = 1; RG char c = getchar(); x = 0;
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
x *= z;
}
const int mod(999911659);
const int phi(999911658);
const int maxn(40000);
int prime[5] = {0, 2, 3, 4679, 35617};
int n, g, fac[5][maxn], inv[5][maxn], ans;
IL int Pow(RG ll x, RG ll y, RG int p){
RG ll ret = 1;
for(; y; y >>= 1, x = x * x % p)
if(y & 1) ret = ret * x % p;
return ret;
}
IL int ExGcd(RG int a, RG int b, RG int &x, RG int &y){
if(!b){
x = 1, y = 0;
return a;
}
RG ll d = ExGcd(b, a % b, y, x);
y -= 1LL * a / b * x;
return d;
}
IL int C(RG int x, RG int y, RG int tp){
return 1LL * fac[tp][x] * inv[tp][y] % prime[tp] * inv[tp][x - y] % prime[tp];
}
IL int Lucas(RG int x, RG int y, RG int tp){
if(y > x) return 0;
if(!y) return 1;
if(x < prime[tp] && y < prime[tp]) return C(x, y, tp);
RG ll ret = Lucas(x % prime[tp], y % prime[tp], tp);
return 1LL * ret * Lucas(x / prime[tp], y / prime[tp], tp) % prime[tp];
}
IL int CRT(RG int k){
RG int x, y, a[5], ret = 0, tmp;
for(RG int i = 1; i <= 4; ++i){
a[i] = Lucas(n, k, i);
ExGcd(tmp = phi / prime[i], prime[i], x, y);
ret = (ret + 1LL * x * a[i] % phi * tmp % phi) % phi;
}
return (ret + phi) % phi;
}
IL void Init(){
for(RG int j = 1; j <= 4; ++j) fac[j][0] = inv[j][0] = 1;
for(RG int j = 1; j <= 4; ++j)
for(RG int i = 1; i < prime[j]; ++i)
fac[j][i] = 1LL * fac[j][i - 1] * i % prime[j];
for(RG int j = 1; j <= 4; ++j)
inv[j][prime[j] - 1] = Pow(fac[j][prime[j] - 1], prime[j] - 2, prime[j]);
for(RG int j = 1; j <= 4; ++j)
for(RG int i = prime[j] - 2; i; --i)
inv[j][i] = 1LL * inv[j][i + 1] * (i + 1) % prime[j];
}
int main(RG int argc, RG char* argv[]){
Input(n), Input(g);
if(g % mod == 0) return puts("0"), 0;
Init();
for(RG int i = 1; i * i <= n; ++i)
if(n % i == 0){
ans = (ans + CRT(i)) % phi;
RG int j = n / i;
if(i != j) ans = (ans + CRT(j)) % phi;
}
printf("%d\n", Pow(g, ans, mod));
return 0;
}