• P2480 [SDOI2010]古代猪文 题解


    0.0

    刷的最后一道数论题,喔,一声长叹~

    Link

    P2480 [SDOI2010]古代猪文

    今天还是来大致描述一下题面好了

    给定(q,n(1≤q,n≤10^9)),计算 (q^{sum_{d|n}C^d_n}mod 999911659)

    Solve

    先考虑特殊情况,如果 (q)(999911659)的倍数,则答案为(0),否则,因为(999911659)是质数,所以(q,n)互质。由欧拉定理的推论得:

    [q^{sum_{d|n}C^d_n} equiv q^{sum_{d|n}C^d_n ext{mod 999911659}} ( ext{mod 999911659}) ]

    因此,我们计算 (q^{sum_{d|n}C^d_n ext{mod 999911659}})

    尝试分解质因数 $999911659=2 ast 3 ast 4679 ast 35617 $。

    然后枚举(n)的约数(d),运用(Lucas)定理求出组合数(C^d_n)。分别计算出(sum_{d|n}C^d_n)(2,3,4679,35617)四个质数取摸的结果,记为(a_1,a_2,a_3,a_4)

    最后用中国剩余定理求解线性同余方程组:

    (egin{cases} ext{x mod 2}=a_1\ ext{x mod 3}=a_2\ ext{x mod 4679}=a_3\ ext{x mod 35617}=a_4\end{cases})

    即可得到(sum_{d|n}C^d_n ext{mod 999911659})的最小非负整数解 (x)。再用快速幂求出 (q^x)即可得到原问题的答案。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL mod=999911658;
    LL n,G,Fc[50005],a[5],b[5]={0,2,3,4679,35617},val;
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
    	return ret*f;
    }
    LL Pow(LL a,LL b,LL p){
    	LL w=a,s=1;
    	while(b){
    		if(b&1)s=w*s%p;
    		w=w*w%p;
    		b>>=1;
    	}
    	return s;
    }
    void make_Fc(LL p){
    	Fc[0]=1;
    	for(int i=1;i<=p;i++)Fc[i]=Fc[i-1]*i%p;
    	return ; 
    }
    LL C(LL n,LL m,LL p){
    	if(n<m)return 0;
    	return Fc[n]*Pow(Fc[m],p-2,p)%p*Pow(Fc[n-m],p-2,p)%p;
    }
    LL Lucas(LL n,LL m,LL 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 CRT(){
    	for(int i=1;i<=4;i++)
    		val=(val+a[i]*(mod/b[i])%mod*Pow(mod/b[i],b[i]-2,b[i]))%mod; 
    }
    int main(){
    //	freopen("P2480.in","r",stdin);
    //	freopen("P2480.out","w",stdout);
    	n=read();G=read();
    	if(G%(mod+1)==0){printf("0
    ");return 0;}
    	for(int k=1;k<=4;k++){
    		make_Fc(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];
    				}
    			}
    		}
    	}
    	CRT();
    	printf("%lld
    ",Pow(G,val,mod+1));
    	return 0;
    }
    
  • 相关阅读:
    【Codeforces542E】Playing on Graph [Bfs][Dfs]
    【Codeforces441E】Valera and Number [DP]
    单链表快速排序
    一个简易内存池(C++)
    最长回文子串---Manacher算法
    hihocoder 1015题
    简单的字典树(前缀树)
    C++获取基类指针所指子类对象的类名
    Muduo阅读笔记---net(三)
    C++线程安全的单例模式
  • 原文地址:https://www.cnblogs.com/martian148/p/13863425.html
Copyright © 2020-2023  润新知