• 洛谷P3807卢卡斯定理


    这是一道模板题

    这里是题目 洛谷P3807

    卢卡斯定理及题目的阐释

    卢卡斯定理是用来解决一大很大的组合数来和一个质数求余的问题,它的定义如下
    如果p为素数,设n=sp+q,m=tp+r
    则:

    那么来看看题。
    首先看这个数据范围,就知道可以用int的类型解决个屁,就是int害的我错了好多次long long 的数据类型解决,这个数据看起来好像是只有 10的5次方,但是中间这么多的计算,突然的就给我溢出了我靠着ZFN大佬的数据测试发现负数才发现的

    long long C(int n,int m,int p){
    	if(n<m)return 0;
    	if(n==m)return 1;
    	if(m>n-m)m=n-m;//约掉 
    	long long s1=1,s2=1;
    	for(int i=0;i<m;i++){
    		s1=s1*(n-i)%p;
    		s2=s2*(i+1)%p;
    	}
    	return s1*qkpow(s2,p-2,p)%p;
    }
    

    这一段是求组合的函数,拿出来单独讲一讲
    因为这里面的参数传过来的时候都是已经和p求过余了的,而且p在题目中说了的,是一个质数所以说这里的n,m都是和p互质的。
    因为公式里面要除掉m!,同时有要去对p取模,所以考虑用它的逆元乘来代替用它来除
    而根据费马小定理可以知道它的逆元是它的p-2

    代码

    那么综上,加上以个快速幂就可以解出这道题了

    //洛谷P3807 Lucas 模板题 
    #include<bits/stdc++.h>
    #define maxn 100005
    using namespace std;
    int n,m,p;
    long long qkpow(long long b,int p,int mod){
    	long long res=1;
    	while(p){
    		if(p&1){
    			(res*=b)%=mod;
    		}
    		(b*=b)%=mod;
    		p>>=1;
    	}
    	return res;
    }
    long long C(int n,int m,int p){
    	if(n<m)return 0;
    	if(n==m)return 1;
    	if(m>n-m)m=n-m;//约掉 
    	long long s1=1,s2=1;
    	for(int i=0;i<m;i++){
    		s1=s1*(n-i)%p;
    		s2=s2*(i+1)%p;
    	}
    	return s1*qkpow(s2,p-2,p)%p;
    }
    long long Lucas(int n,int m,int p){
    	if(m==0)return 1;
    	return C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
    }
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("input.txt","r",stdin);
    	freopen("output.txt","w",stdout);
    	#endif
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d%d",&n,&m,&p);
    		n+=m;
    		cout<<Lucas(n,m,p)<<"
    ";
    	}
    	return 0;
    }
    
  • 相关阅读:
    js弹出遮罩层
    委托集合使用
    C#动态属性(.NET Framework4.5支持)
    ABP项目启动及源代码结构
    ABP项目概述
    Visual Studio 2017调试开源项目代码
    GIT的前世今生
    近期上海面试总结(二)
    近期上海面试总结(一)
    一个基于反射的消息发布订阅模型详解
  • 原文地址:https://www.cnblogs.com/perisino/p/10263165.html
Copyright © 2020-2023  润新知