bzoj 1951 [Sdoi2010]古代豬文

zzk_233發表於2018-10-28

這是一道數論集合題

求式子g^{\sum_{m|n} C_{n}^{m}} \ mod \ 999911659,首先可以先用尤拉定理將式子降冪為指數mod (999911659-1)。

而對於指數可以在根號n的時間內列舉每個約數,對於每個約數求相應的組合數,可以用lucas定理來求解,

但是因為這個模數不是指數,所以把這個模數拆開,再用中國剩餘定理合併就好了

999911658=2*3*4679*35617

注意的點是當g等於999911659時,這個定理不適用,但顯然答案是0,所以要特判掉。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define mode 999911658
using namespace std;
typedef long long ll;
ll n,g,x,y;
ll mod[5]={0,2,3,4679,35617};
ll niv[5][40005],jc[5][40005],ans[5],tot;
void gett(int u)
{
	niv[u][1]=1;
	for(int i=2;i<mod[u];i++)
	{
		niv[u][i]=(mod[u]-mod[u]/i)*niv[u][mod[u]%i]%mod[u];
	}
	jc[u][0]=1;
	for(int i=1;i<mod[u];i++)
	{
		jc[u][i]=jc[u][i-1]*i%mod[u];
	}
	niv[u][0]=1;
	for(int i=1;i<mod[u];i++)
	{
		niv[u][i]=niv[u][i-1]*niv[u][i]%mod[u];
	}
}
ll exgcd(ll a,ll b)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	ll r=exgcd(b,a%b);
	ll t=x;
	x=y;
	y=t-a/b*x;
	return r;
}
ll Lucas(ll x,ll y,int u)
{
	if(x==0)return 1;
	if(y%mod[u]<x%mod[u])return 0;
	return Lucas(x/mod[u],y/mod[u],u)%mod[u]*jc[u][y%mod[u]]%mod[u]*niv[u][x%mod[u]]%mod[u]*niv[u][((y-x)%mod[u]+mod[u])%mod[u]]%mod[u];
}
ll crt(int u)
{
	ll as=0;
	for(int i=1;i<=4;i++)
	{
		ans[i]=Lucas(u,n,i);
		ll gg=exgcd(mode/mod[i],mod[i]);
		ans[i]/=gg;
		x=(x%mod[i]+mod[i])%mod[i];
		x*=ans[i]%mode;x%=mode;
		as+=x*mode/mod[i]%mode;
		as%=mode;
	}
	return as;
}
void ys(ll u)
{
	for(ll i=1;i*i<=u;i++)
	{
		if(u%i==0)
		{
			tot+=crt(i)%mode;
			tot%=mode;
			if(i*i==u)continue;
			tot+=crt(u/i)%mode;
			tot%=mode;
		}
	}
}
ll ksm(ll x,ll y)
{
	ll as=1;
	while(y)
	{
		if(y%2==1)
		{
			as=as*x%(mode+1);
		}
		x=x*x%(mode+1);
		y=y/2;
	}
	return as;
}
int main()
{
	scanf("%lld%lld",&n,&g);
	if(g==mode+1)
	{
		printf("0");
		return 0;
	}
	for(int i=1;i<=4;i++)gett(i);
	ys(n);
	printf("%lld",ksm(g,tot)%(mode+1));
	return 0;
}