题目链接

题目大意:给定\(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;
}

相关文章:

  • 2021-10-13
  • 2021-11-03
  • 2022-03-02
  • 2022-01-08
  • 2022-02-18
  • 2021-08-09
猜你喜欢
  • 2021-08-02
  • 2021-09-30
  • 2022-01-15
  • 2021-11-20
  • 2021-06-07
  • 2021-06-15
相关资源
相似解决方案