[SDOI2010]古代猪文

题目:
https://ac.nowcoder.com/acm/problem/20333



G ∑ d ∣ n ( n i )   m o d    999911659 G^{\sum_{d|n}{n\choose i}}\ mod\;999911659 Gdn(in) mod999911659

思路:

G ∑ d ∣ n ( n i )   m o d    p = G ( ∑ d ∣ n ( n i ) ) m o d    p − 1   m o d    p \begin{aligned} &G^{\sum_{d|n}{n\choose i}}\ mod\;p\\ =&G^{(\sum_{d|n}{n\choose i})mod\;p-1}\ mod\;p\\ \end{aligned} =Gdn(in) modpG(dn(in))modp1 modp
p − 1 = 2 × 3 × 4697 × 35617 p-1=2×3×4697×35617 p1=2×3×4697×35617
中国剩余定理 + L u c a s +Lucas +Lucas
∑ d ∣ n ( n i ) ≡ x   m o d    p − 1 ⟺ { ∑ d ∣ n ( n    m o d    2 i    m o d    2 ) ≡ x   m o d    2 ∑ d ∣ n ( n    m o d    3 i    m o d    3 ) ≡ x   m o d    3 ∑ d ∣ n ( n    m o d    4697 i    m o d    4697 ) ≡ x   m o d    4697 ∑ d ∣ n ( n    m o d    35617 i    m o d    35617 ) ≡ x   m o d    35617 \sum_{d|n}{n\choose i}\equiv x\ mod\;p-1\Longleftrightarrow \begin{cases} \sum_{d|n}{n\;mod\;2\choose i\;mod\;2}\equiv x\ mod\;2\\ \sum_{d|n}{n\;mod\;3\choose i\;mod\;3}\equiv x\ mod\;3\\ \sum_{d|n}{n\;mod\;4697\choose i\;mod\;4697}\equiv x\ mod\;4697\\ \sum_{d|n}{n\;mod\;35617\choose i\;mod\;35617}\equiv x\ mod\;35617\\ \end{cases} dn(in)x modp1dn(imod2nmod2)x mod2dn(imod3nmod3)x mod3dn(imod4697nmod4697)x mod4697dn(imod35617nmod35617)x mod35617

最后再用一下快速幂即可。

注意:
G = p G=p G=p时,输出 0 0 0

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int mod=999911658;
LL n,G,farc[50010],a[5],b[5]={0,2,3,4679,35617},val;

LL fast_pow(LL a,LL b,LL p)//快速幂
{
	LL ret=1;
	for(;b;b>>=1,a=a*a%p)
		ret=ret*(b&1?a:1)%p;
	return ret;
}

void init(LL p)//预处理
{
	farc[0]=1;
	for(LL i=1;i<=p;i++)
		farc[i]=farc[i-1]*i%p;
}

LL C(LL n,LL m,LL p)//组合数
{
	if(n<m) return 0;
	return farc[n]*fast_pow(farc[m],p-2,p)%p*fast_pow(farc[n-m],p-2,p)%p;
}

LL Lucas(LL n,LL m,LL p)//Lucas定理
{
	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(LL i=1;i<=4;i++)
		val=(val+a[i]*(mod/b[i])%mod*fast_pow(mod/b[i],b[i]-2,b[i]))%mod;
}

int main()
{
	scanf("%lld%lld",&n,&G);
	if(G%(mod+1)==0){
		printf("0\n");
		return 0;
	}//特判
	for(LL k=1;k<=4;k++){
		init(b[k]);
		for(LL 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];
				}
			}
		}
	}//逐一枚举n的约数
	CRT();
	printf("%lld\n",fast_pow(G,val,mod+1));//注意mod要+1
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值