【洛谷2480】[SDOI2010] 古代猪文(卢卡斯定理+中国剩余定理)

点此看题面

  • 给定(n,g),求(g^{sum_{d|n}C_n^d}(mod 999911659))
  • (n,gle10^9)

卢卡斯定理+中国剩余定理

只考虑(sum_{d|n}C_n^d)一项,那么也就是要求它在模(999911658)意义下的结果。

尽管模数不是质数,其实我们没必要跑扩展卢卡斯,直接把模数拆开得到(999911658=2 imes3 imes4679 imes35167)

对于四个模数分别跑卢卡斯定理求组合数,然后用中国剩余定理合并起来就结束了。

(O(sqrt nlogn))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define X 999911659
using namespace std;
int n,g;const int p[4]={2,3,4679,35617};
I int QP(RI x,RI y,CI p) {RI t=1;W(y) y&1&&(t=1LL*t*x%p),x=1LL*x*x%p,y>>=1;return t;}
int Fac[4][35617],IFac[4][35617];I void InitFac(CI id)//分别预处理四种模意义下的阶乘和阶乘逆元
{
	RI i;for(Fac[id][0]=i=1;i^p[id];++i) Fac[id][i]=1LL*Fac[id][i-1]*i%p[id];
	for(IFac[id][i=p[id]-1]=QP(Fac[id][p[id]-1],p[id]-2,p[id]);i;--i) IFac[id][i-1]=1LL*IFac[id][i]*i%p[id];
}
I int C(CI id,CI n,CI m)//卢卡斯定理求组合数
{
	if(n<m) return 0;if(n<p[id]&&m<p[id]) return 1LL*Fac[id][n]*IFac[id][m]%p[id]*IFac[id][n-m]%p[id];
	return 1LL*C(id,n/p[id],m/p[id])*C(id,n%p[id],m%p[id])%p[id];
}
I void CRT(int& r1,int& p1,CI r2,CI p2) {RI k=1LL*((r2-r1)%p2+p2)*QP(p1,p2-2,p2)%p2;r1=k*p1+r1,p1*=p2;}//中国剩余定理合并
I int Calc(CI x) {RI i,t=0,w=1;for(i=0;i^4;++i) CRT(t,w,C(i,n,x),p[i]);return t;}//分别对四个模数求组合数,然后合并
int main()
{
	RI i,t=0;for(i=0;i^4;++i) InitFac(i);
	if(scanf("%d%d",&n,&g),!(g%X)) return puts("0"),0;
	for(i=1;i*i<=n;++i) !(n%i)&&(t=(t+Calc(i))%(X-1),i^(n/i)&&(t=(t+Calc(n/i))%(X-1)));//枚举n的因数
	return printf("%d
",QP(g,t,X)),0;
}