题解 BZ1951 【[SDOI2010]古代猪文】

[SDOI2010]古代猪文

题目大意:

给定 \(n,g\) ,求:

\[g^{\sum\limits_{i=1,i\mid n}^{n}C_{n}^{i}}\bmod 999911659 \]

solution:

模数是质数,有费马小定理,原式变为:

\[g^{\sum\limits_{i=1,i\mid n}^{n}C_{n}^{i}\bmod 999911658}\bmod 999911659 \]

但直接通过 \(\text{Lucas}\) 定理计算组合数也不被允许,所以我们把 \(999911658\) ,分解下质因数:\(999911658=2\times 3\times 4679\times 35617\)
我们设 \(a_1=\sum\limits_{i=1,i\mid n}^{n}C_{n}^{i}\bmod 2,a_2=\sum\limits_{i=1,i\mid n}^{n}C_{n}^{i}\bmod 3,a_3=\sum\limits_{i=1,i\mid n}^{n}C_{n}^{i}\bmod 4679,a_4=\sum\limits_{i=1,i\mid n}^{n}C_{n}^{i}\bmod 35617\)
对于 \(g\) 的幂次 \(p\) ,有:

\[\begin{cases} p\equiv a_1 \pmod 2\p\equiv a_2 \pmod 3\p\equiv a_3 \pmod {4679}\p\equiv a_4 \pmod {35617} \end{cases}\]

\(\text{CRT}\) 求解即可。

细节处理:

  • 对于 \(g=999911659\) 要进行特判,因为此时 \(g\) 的几次幂都不可能为 \(0\) ,而此时答案显然为 \(0\)
代码
#include<cstdio>
using namespace std;
typedef long long LL;
const int N=40000,mod=999911659,M=999911658;
int a[5],mi[5]={0,2,3,4679,35617};
int fac[N],inv[N];
inline int qpow(int x,int b,int p){
	int res=1;
	while(b){
		if(b&1) res=(LL)res*x%p;
		x=(LL)x*x%p;
		b>>=1;
	}
	return res;
}
inline void Fac(int p){
	fac[0]=1;
	for(int i=1;i<=p;i++)//实际上到 p-1 即可
		fac[i]=(LL)fac[i-1]*i%p;
}
inline void Inv(int p){
	inv[p-1]=qpow(fac[p-1],p-2,p);//需要用 fac[p-1] 往回推。
	for(int i=p-2;i>=0;i--)
		inv[i]=(LL)inv[i+1]*(i+1)%p;
}
inline int C(int n,int m,int p){
	if(n<m) return 0;//此处特判
	return (LL)fac[n]*inv[m]%p*inv[n-m]%p;
}
inline int Lucas(int n,int m,int p){
	if(!m) return 1;//特判
	return (LL)C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
}
inline void div(int n){
	for(int i=1;i<=4;i++){
		Fac(mi[i]),Inv(mi[i]);
		for(int j=1;j<=n/j;j++){//n/j防止越界
			if(n%j!=0) continue;
			a[i]=((LL)a[i]+Lucas(n,j,mi[i]))%mi[i];
			if((LL)j*j!=n)
				a[i]=((LL)a[i]+Lucas(n,n/j,mi[i]))%mi[i];
		}
	}
}
inline int CRT(){
	int ans=0;
	for(int i=1;i<=4;i++){
		int Mi=M/mi[i];
		int t=qpow(Mi,mi[i]-2,mi[i]);//费马小定理求逆元
		ans=((LL)ans+(LL)a[i]*Mi%M*t%M)%M;
	}
	return ans;
}
int main(){
	int n,g; scanf("%d%d",&n,&g); 
	if(g%mod==0) return puts("0"),0;//特判
	div(n);//求约数 O(sqrt(n))
	int p=CRT();//中国剩余定理和并解
	printf("%d",qpow(g,p,mod));
	return 0;
}

End

题解 BZ1951 【[SDOI2010]古代猪文】

上一篇:高精全家桶


下一篇:用输入法敲打键盘时字体之间的间隔突然变大了,是怎么回事?