P2480 [SDOI2010]古代猪文 题解

0.0

刷的最后一道数论题,喔,一声长叹~

Link

P2480 [SDOI2010]古代猪文

今天还是来大致描述一下题面好了

给定(q,n(1≤q,n≤10^9)),计算 (q^{sum_{d|n}C^d_n}mod 999911659)

Solve

先考虑特殊情况,如果 (q)(999911659)的倍数,则答案为(0),否则,因为(999911659)是质数,所以(q,n)互质。由欧拉定理的推论得:

[q^{sum_{d|n}C^d_n} equiv q^{sum_{d|n}C^d_n ext{mod 999911659}} ( ext{mod 999911659}) ]

因此,我们计算 (q^{sum_{d|n}C^d_n ext{mod 999911659}})

尝试分解质因数 $999911659=2 ast 3 ast 4679 ast 35617 $。

然后枚举(n)的约数(d),运用(Lucas)定理求出组合数(C^d_n)。分别计算出(sum_{d|n}C^d_n)(2,3,4679,35617)四个质数取摸的结果,记为(a_1,a_2,a_3,a_4)

最后用中国剩余定理求解线性同余方程组:

(egin{cases} ext{x mod 2}=a_1\ ext{x mod 3}=a_2\ ext{x mod 4679}=a_3\ ext{x mod 35617}=a_4\end{cases})

即可得到(sum_{d|n}C^d_n ext{mod 999911659})的最小非负整数解 (x)。再用快速幂求出 (q^x)即可得到原问题的答案。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=999911658;
LL n,G,Fc[50005],a[5],b[5]={0,2,3,4679,35617},val;
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
LL Pow(LL a,LL b,LL p){
	LL w=a,s=1;
	while(b){
		if(b&1)s=w*s%p;
		w=w*w%p;
		b>>=1;
	}
	return s;
}
void make_Fc(LL p){
	Fc[0]=1;
	for(int i=1;i<=p;i++)Fc[i]=Fc[i-1]*i%p;
	return ; 
}
LL C(LL n,LL m,LL p){
	if(n<m)return 0;
	return Fc[n]*Pow(Fc[m],p-2,p)%p*Pow(Fc[n-m],p-2,p)%p;
}
LL Lucas(LL n,LL m,LL p){
	if(n<m)return 0;if(!n)return 1;
	return Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
void CRT(){
	for(int i=1;i<=4;i++)
		val=(val+a[i]*(mod/b[i])%mod*Pow(mod/b[i],b[i]-2,b[i]))%mod; 
}
int main(){
//	freopen("P2480.in","r",stdin);
//	freopen("P2480.out","w",stdout);
	n=read();G=read();
	if(G%(mod+1)==0){printf("0
");return 0;}
	for(int k=1;k<=4;k++){
		make_Fc(b[k]);
		for(int i=1;i*i<=n;i++){
			if(n%i==0){
				a[k]=(a[k]+Lucas(n,i,b[k]))%b[k];
				if(i*i!=n){
					a[k]=(a[k]+Lucas(n,n/i,b[k]))%b[k];
				}
			}
		}
	}
	CRT();
	printf("%lld
",Pow(G,val,mod+1));
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/13863425.html