bzoj1951: [Sdoi2010]古代猪文

集各比较重要的数论定理于一身的题

如果没学过快速幂、费马小定理、lucas定理、中国剩余定理的,请出门右转文化课,OI不适合你,请出门左转自行百度/google

学完了这题就是大傻逼题了

另外注意特判G=P时,费马小定理不成立,直接输出0

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define ll long long

using namespace std;
const int P0=999911659; 
const int P1=999911658;
const int p[4]={35617,4679,3,2};

int pow(int x,int y,int P){
	int ret=1;
	while (y){
		if (y&1) ret=(ll)ret*x%P;
		x=(ll)x*x%P;
		y=y>>1;
	}
	return ret;
}

int inv(int x,int P){return pow(x,P-2,P);}

int fact[66666];
int C(int n,int m,int P){
	if (n<m) return 0;
	return (ll)fact[n]*inv(fact[n-m],P)%P*inv(fact[m],P)%P;
}
int lucas(int n,int m,int P){
	if (!n&&!m) return 1;
	return (ll)lucas(n/P,m/P,P)*C(n%P,m%P,P)%P;
}

int n,G;
int main(){
	scanf("%d%d",&n,&G);
	if (G==P0){puts("0");return 0;}
	for (int i=fact[0]=1;i<=p[0];++i) fact[i]=(ll)fact[i-1]*i%P1;
	int tot=0;
	for (int k=0;k<4;++k){
		int now=0;
		for (int i=1;i*i<=n;++i)if (n%i==0){
			(now+=lucas(n,i,p[k]))%=p[k];
			if (n/i!=i)
				(now+=lucas(n,n/i,p[k]))%=p[k];
		}
		(tot+=(ll)now*(P1/p[k])%P1*inv(P1/p[k],p[k])%P1)%=P1;
	}
	printf("%d\n",pow(G,tot,P0));
	return 0;
}

  

你可能感兴趣的:(bzoj1951: [Sdoi2010]古代猪文)