P2480 SDOI 古代猪文(自带其他详细基础数论)

P2480 SDOI2010古代猪文

题目大意:求

\(G^{\sum_{d|n}{n \choose d}}~mod~999911659\)

各种基础数论全家桶,做这个题相当于复习今天内容了

999911659为质数

费马小定理\(a^p\equiv a(mod~p)\),\(a^p~mod~p=a~mod~p\)

\(p是质数时,φ(p)=p-1,根据欧拉定理推论a^b\equiv a^{b~mod~φ(n)}=a^{b~mod~(p-1)}(mod~n)\)

化简可得\(a^{\sum d|nC_n^d~mod~999911658}mod999911659\)

质因数分解\(999911658 = 2*3*4679*35617\)

\(枚举每个d,再用个Lucas定理或其他鬼方法把C_n^d算出来,分别计算\sum C_n^d对四个质数取模结果记为a_1,a_3,a_3,a_4\)

跑个中国剩余定理

中国剩余定理:\(m_i是两两互质的整数,m=\prod_{i=1}^nm_i,M_i=m/m_i,t_i\)是线性同余方程\(M_it_i\equiv1(mod~m_i)\)

的一个解,对于任意的n个整数\(a_i\),方程组有整数解为\(x=\sum_{i=1}^na_iM_it_i\)

\[\left\{ \begin{aligned} x & \equiv a_1(mod~2) \\ x & \equiv a_2(mod~3) \\ x&\equiv a_3(mod~4679)\\ x&\equiv a_4(mod~35617)\\ \end{aligned} \right. \]

#include<cstdio>
#define maxn
#define mod 999911658
#define int long long
using namespace std;
int n,G,jc[40000],a[5],b[5]={0,2,3,4679,35617},ans;
inline int qpow(int a,int k,int p)
{
	int res=1;
	while(k)
	{
		if(k&1) res=(res*a)%p;
		a=(a*a)%p;
		k>>=1;
	}
	return res%p;
}
void jiecheng(int p){
	jc[0] = 1;
	for(int i = 1;i<=p;i++)
	jc[i] = jc[i-1] * i % mod;
}
int C(int n,int m,int p){
	if(n < m) return 0;
	return jc[n] * qpow(jc[m],p-2,p) % p * qpow(jc[n-m],p-2,p) % p;
}
int lucas(int n,int m,int p){
	if(n<m) return 0;if(!n) return 1;
	return lucas(n/p,m/p,p)*C(n % p,m % p,p) % p;
}
void zgsy(){
	for(int i=1;i<=4;i++)
	ans=(ans+a[i]*(mod/b[i])%mod*qpow(mod/b[i],b[i]-2,b[i]))%mod;
}
signed main(){
	scanf("%lld%lld",&n,&G);
	if(G%(mod+1)==0){
		printf("0\n");
		return 0;
	}//特判
	for(int k=1;k<=4;k++){
		jiecheng(b[k]);
		for(int 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的约数
	zgsy();
	printf("%lld\n",qpow(G,ans,mod+1));//注意mod要+1
	return 0;
}

\[计算组合数的几种方法:\\ 1.递推杨辉三角C_n^m=C_{n-1}^m+C_{n-1}^{m-1}~C[0][0]=C[1][0]=1,求一个组合数可以滚动,倒着枚举,代码如下\\ 2.乘法逆元:**这种方法只适用于对答案模一个大质数的情况**,根据通项公式预处理阶乘算逆元乱搞\\ 质数一定要大\\ 3.Lucas定理:C_n^m=C_{n/p}^{m/p}*C_{n\%p}^{m\%p}(mod~p)\\ 4.质因数分解,要乘或除的每一个数分解质因数,再把分母的质因数减掉,最后把剩下的质因数乘起来,边乘边模p \]

//一维递推组合数
	cin>>n>>m;
    m=min(m,n-m);
    c[0]=1;
    for (int i=1;i<=n;i++)
    {
        for (int j=m;j>=1;j--)
    	c[j]=c[j]+c[j-1];
    }
    cout<<c[m];
//线性推逆元
long long inv[10000005];
inv[1]=1;
long long ny(int x,int p)
{
    if (inv[x] != 0) return inv[x];
    inv[x]=(p - p / x) * ny(p % x,p) % p;
    return inv[x];
}
//费马小定理求逆元 a mod p乘法逆元=a^(p-2)
快速幂`````
qpow(a,p-2)
//扩欧
void exgcd(LL a, LL b, LL &x, LL &y)    //拓展欧几里得算法
{
    if(!b) x = 1, y = 0;
    else
    {
        exgcd(b, a % b, y, x);
        y -= x * (a / b);
    }
}
LL niYuan(LL a, LL b)   //求a对b取模的逆元
{
    LL x, y;
    exgcd(a, b, x, y);
    return (x + b) % b;
}

猜你喜欢

转载自www.cnblogs.com/shikeyu/p/13369096.html