BZOJ 1951 【SDOI2010】 古代猪文

题目链接:古代猪文

  好久没写博客了,这次就先写一篇吧……

  题面好鬼……概括起来就是:给出\(N,G(\leqslant 10^9)\),求:\[G^{\sum_{d|n}\binom{n}{d}} \bmod p \]

  其中\(p=999911659\),是一个质数。

  首先,当\(G\neq p\)时,由欧拉定理可知\[G^x\equiv G^{x\bmod(p-1)}(\bmod p)\]

  然后我们实际上就是要快速计算\[\sum_{d|n}\binom{n}{d} \bmod(p-1)\]

  由于\(p-1\)不是一个质数,我们可以把它给质因数分解了,得到\(p-1=2\times 3\times 4679\times 35617\)

  然后分别在模这些数的情况下用\(Lucas\)定理算出组合数,再中国剩余定理合并。用中国剩余定理的时候注意有多个模数,不要弄混了。

  复习一下\(Lucas\)定理,当\(p\)为质数时,有:\[\binom{a}{b} \equiv \binom{\lfloor \frac{a}{p} \rfloor}{\lfloor \frac{b}{p} \rfloor} \binom{a\bmod p}{b\bmod p}(\bmod p)\]

  中国剩余定理复习:xlightgod的博客Mashirosky的博客

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define mod 999911659
#define maxn 40010

using namespace std;
typedef long long llg;

int n,g,pr,pk,pri[4]={2,3,4679,35617};
llg jie[4][maxn],ni[4][maxn],zhi;

llg mi(llg a,int b){
	llg s=1;
	while(b){
		if(b&1) s=s*a%pr;
		a=a*a%pr; b>>=1;
	}
	return s;
}

llg C(int x,int y){return x<y?0:jie[pk][x]*ni[pk][y]%pr*ni[pk][x-y]%pr;}
llg lucas(int x,int y){
	if(!y) return 1; if(x<y) return 0;
	return lucas(x/pr,y/pr)*C(x%pr,y%pr)%pr;
}

llg hebing(int x,int y){
	llg now=0;
	for(int k=0;k<4;k++){
		pr=pri[k],pk=k;
		now+=(mod-1)/pr*mi((mod-1)/pr,pr-2)*lucas(x,y);
		now%=mod-1;
	}
	return now;
}

int main(){
	File("a");
	scanf("%d %d",&n,&g);
	if(mod==g){putchar('0');return 0;}
	for(int k=0;k<4;k++){
		jie[k][0]=1; pr=pri[k]; pk=k;
		for(int i=1;i<pr;i++) jie[k][i]=jie[k][i-1]*i%pr;
		ni[k][pr-1]=mi(jie[k][pr-1],pr-2);
		for(int i=pr-1;i;i--) ni[k][i-1]=ni[k][i]*i%pr;
	}
	for(int d=1,l=sqrt(n);d<=l;d++)
		if(n%d==0){
			zhi+=hebing(n,d);
			if(n/d!=d) zhi+=hebing(n,n/d);
			zhi%=(mod-1);
		}
	pr=mod; printf("%lld",mi(g,zhi));
	return 0;
}
posted @ 2017-01-13 10:33  lcf2000  阅读(216)  评论(0编辑  收藏  举报