题目大意:给定\(G\),\(n\),求\(G^{\sum_{d \mid n}C_n^d} \; mod\;999911659\)
欧拉定理,卢卡斯定理,EXCRT
分析:
我们发现问题的关键在于指数,然后答案可以用快速幂计算
首先我们观察模数,写个小程序发现\(999911659\)是个质数,于是我们可以用欧拉定理把指数缩小
若\(gcd(a,p)=1\),有\(a^b \equiv a^{b\;mod\;\phi(p)}\;mod\;p\)
如果你\(95\)的话不妨加一个特判
好像也可以扩展欧拉定理不过哪儿那么麻烦
然后我们要求\(\sum_{d \mid n}C_n^d \; mod\;999911658\)
\(n\)的所有约数我们可以\(O(\sqrt{n})\)枚举,不用\(O(n)\)因为约数成对出现
然后\(C_n^d \; mod\;999911658\)这玩意儿可以扩展卢卡斯定理,但是这个模数比较特殊。我怀疑出题人是精心选取过的
\(999911658=2 \times 3 \times 4679 \times 35617\)
它有\(4\)个质因子并且指数都为\(1\)
我们可以分别对上述\(4\)个质因子取膜,EXCRT合并即可
//2 * 3 * 4679 * 35617
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxp = 36000;
ll qpow(ll a,ll b,ll mod){
a %= mod;
ll res = 1,base = a;
while(b){
if(b & 1)res = (res * base) % mod;
base = (base * base) % mod;
b >>= 1;
}
return res;
}
ll gcd(ll a,ll b){return !b ? a : gcd(b,a % b);}
ll lcm(ll a,ll b){return a / gcd(a,b) * b;}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x = 1,y = 0;
return a;
}
ll res = exgcd(b,a % b,y,x);
y -= (a / b) * x;
return res;
}
ll mul(ll a,ll b,ll p){return (a * b) % p;}
struct Lucas{
ll fac[maxp],inv[maxp],p;
inline void init(ll x){
p = x,fac[0] = 1,inv[0] = qpow(fac[0],p - 2,p);
for(int i = 1;i <= p;i++)
fac[i] = (fac[i - 1] * i) % p,inv[i] = qpow(fac[i],p - 2,p);
}
inline ll C(ll n,ll m){
return m > n ? 0 : mul(fac[n],mul(inv[m],inv[n - m],p),p);
}
inline ll lucas(ll n,ll m){
return !m ? 1 : (lucas(n / p,m / p) * C(n % p,m % p)) % p;
}
}lucas[8];
ll n,base,exp,b[8],m[8] = {0,2,3,4679,35617};
inline ll excrt(){
ll M = m[1],res = b[1];
for(int i = 2;i <= 4;i++){
ll t,k,s = ((b[i] - res) % m[i] + m[i]) % m[i];
ll r = exgcd(M,m[i],t,k);
if(s % r)return -1;
t = mul(t,s / r,m[i] / r);
res += t * M;
M = lcm(M,m[i]);
res = (res % M + M) % M;
}
return res;
}
int main(){
scanf("%lld %lld",&n,&base);
if(!(base % 999911659))return printf("0\n"),0;
for(int i = 1;i <= 4;i++)lucas[i].init(m[i]);
for(int i = 1;i * i <= n;i++)
if(!(n % i))
for(int k = 1;k <= 4;k++){
b[k] += lucas[k].lucas(n,i);
if(i != n / i)b[k] += lucas[k].lucas(n,n / i);
}
exp = excrt();
printf("%lld\n",qpow(base,exp,999911659));
return 0;
}