suxxsfe

一言(ヒトコト)

P2480 [SDOI2010]古代猪文

P2480 [SDOI2010]古代猪文

比较综合的一题
前置:Lucas 定理crt

求的是:

\[g^x\bmod 999911659,\text{其中}x=\sum_{d\mid n}\tbinom{n}{d} \]

由于这个\(999911659\)是质数,肯定于\(g\)互质,所以由欧拉定理很容易证明:

\[a^{\varphi(p)}\equiv 1\pmod p\Rightarrow a^{k\bmod \varphi(p)}\equiv a^k\pmod p \]

那么可以得出:

\[g^x\bmod 999911659\equiv g^{x\bmod \varphi(999911659)}\pmod {999911659} \]

\[g^x\bmod 999911659\equiv g^{x\bmod 999911658}\pmod {999911659} \]

所以问题转换为求:

\[\sum_{d\mid n}\tbinom{n}{d}\bmod 999911658 \]

这种大组合数的问题考虑用 Lucas,但是模数太大,且不是质数
所以考虑将它分解:\(999911658=2\times 3\times 4679\times 35617\)
那么,只需要对每一个质因数,求出\(a\equiv \sum_{d\mid n}\tbinom{n}{d}\bmod p_i\),然后再用 crt 合并就行了

算的时候,枚举每一个\(i\le \sqrt n\),如果\(i\mid n\),则计算\(\tbinom{n}{i}\)\(\tbinom{n}{\frac{n}{i}}\)加到答案里
但是,在这种因数不能重复计算的时候,要:

for(reg int i=1;i*i<=n;i++)

而不是

for(reg int i=1;i<=std::ceil(std::sqrt(n));i++)

对于后一种,举个栗子:\(\lceil\sqrt {420}\rceil=21\),但是如果\(i\)一直枚举到\(21\),就会在\(i=20,i=21\)的时候算两次\(20,21\)这两个因数,重复了,出现错误

还有,因为每次的计算模数不同,所以要分别预处理

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
const int prime[4]={2,3,4679,35617};
int fac[40006],inv[40005];
inline int power(int a,int b,int p){
	int ret=1;
	while(b){
		if(b&1) ret=1ll*ret*a%p;
		b>>=1;a=1ll*a*a%p;
	}
	return ret;
}
inline void pre(int n,int mod){
	fac[0]=inv[0]=1;
	for(reg int i=1;i<n;i++) fac[i]=(LL)fac[i-1]*i%mod;
	inv[n-1]=power(fac[n-1],mod-2,mod);
	for(reg int i=n-2;i;i--) inv[i]=(LL)inv[i+1]*(i+1)%mod;
}
inline int get_C(int n,int m,int mod){
	//C(n,m)=n!/(m!*(n-m)!)
	if(n<m) return 0;
	return ((LL)fac[n]*inv[m]%mod)*inv[n-m]%mod;
}
inline int lucas(int n,int m,int mod){
	if(n<m) return 0;
	if(!n||!m) return 1;
	return (LL)lucas(n/mod,m/mod,mod)*get_C(n%mod,m%mod,mod)%mod;
}
int main(){
//	std::freopen("out.txt","w",stdout);
	const int M=999911658;
	int n=read(),g=read();
	g%=(M+1);
	if(!g) return std::puts("0"),0;
	reg int ans=0,Mi,t;
	for(reg int o=0;o<4;o++){
		pre(prime[o],prime[o]);
		reg int nowans=0;
		for(reg int i=1;i*i<=n;i++)if(!(n%i)){
			nowans=(nowans+lucas(n,i,prime[o]))%prime[o];
			if(i*i!=n) nowans=((LL)nowans+lucas(n,n/i,prime[o]))%prime[o];
		}
//			std::printf("now ans = %d\n",nowans);
//			for(reg int i=0;i<prime[o];i++) std::printf("%d %d\n",fac[i],inv[i]);
		Mi=M/prime[o];
		t=power(Mi,prime[o]-2,prime[o]);//t=Mi^{-1} mod prime[o]
		ans=(ans+((LL)nowans*Mi%M*t%M))%M;
	}
	std::printf("%d",power(g,ans,M+1));
	return 0;
}
posted @ 2020-04-10 18:30  suxxsfe  阅读(131)  评论(0编辑  收藏  举报