数论总结之Lucas
2017-06-10 11:08
190 查看
Lucas定理
主要用来处理大组合数取模(模数是质数)的问题
内容:C(n,m)=C(n/p,m/p)*C(n%p,m%p)%p (n/p依旧是向下取整)
证明:Lucas定理的另一种表现方式:
C(sp+q,tp+r)≡C(s,t)*C(q,r)(mod p)
首先:1+x^(sp+q)=((1+x)^p)^s*(1+x)^q
所以:(1+x)^(sp+q)≡Σi=0…s C(s,i)x^(i*p)Σ(i=0…q)C(q,i)*x^i (利用二项式定理)
令右式i=t,j=r则右式x^(tp+r)系数为 C(s,t)*C(q,r);
对左式直接使用二项式定理
令左式i=tp+r,则左式x^(tp+r)系数为C(sp+q,tp+r);
所以得证。
关于Lucas定理的扩展:
对于模数p
1.p是素数
2.p不是素数
又可分为(1).分解完质数后每个质因子只出现一次
(2).分解完质数后每个质因子出现不止一次
3.p不是素数但p=m^t(m为素数)
处理方式:
对1 直接运用Lucas定理即可求解
对2(1) 可以运用Lucas求对p的每个质因子的模,再运用中国剩余定理将模数合并(又引出了一个flag)
对2(2) 对出现不止一次的质因子,则每个质因子的n次幂跟3一样处理,然后再运用中国剩余定理合并
对3
因为C(n,m)=n!/(m!(n-m)!)
所以我们可以分为三部分求解:n!%p^t,m!%p^t,(n-m)!%p^t 再逆元就可求解。
·求n!%p^t:
1.求p的幂,即p^(n/p) (快速幂)
2.新的阶乘 即(n/p)! (递归)
3.剩下部分 模p^t意义下以p^t为周期,所以求p^t长度就可。
剩下孤立的数长度不会超过p^t,暴力求解就可。
·关于m!%p^t和(n-m)!%(p^t)
方法大致与上述相同 但因为不互质就无法求逆元,所以应先除去质因子,求出逆元后再乘回去。
补充:
计算n!的质因子p的个数x为:
x=(n/p)+(n/(p^2))+(n/(p^3))+…
递推:f
=f[n/p]+n/p; //n/p均为向下取整
题【板】:
hdu 3037[感觉我做的题都还是挺水的]
[这道题是好久以前做的都快不记得题面了]
[也当留个板吧]
大概看了一下代码,其实就是跟Lucas的内容差不多,递归实现,但是具体实现有一些要注意的小细节而已。
【下面的内容有毒】
如果在考试的时候,出现了一道考Lucas的题目,但是已经很久没有打过Lucas了,也特别担心自己Lucas写炸,那怎么办。。
这个时候我们也可以根据组合数的计算方式暴力用求逆元水过去2333
沈阳集训Day2T1
题面:计算C(m,n) mod 9901 的值
数据范围:n<=m<=20000
【就是这么一道水题】【我还将它变得更水了23333】
【我估计整个班只有我一个人是这样做的。。。】
代码如下【每个部分都清楚易懂】:
在考试的时候即使觉得自己打不出来正解,也不要轻言放弃
有很多其他杂七杂八的算法
万一就水过去了呢233333
主要用来处理大组合数取模(模数是质数)的问题
内容:C(n,m)=C(n/p,m/p)*C(n%p,m%p)%p (n/p依旧是向下取整)
证明:Lucas定理的另一种表现方式:
C(sp+q,tp+r)≡C(s,t)*C(q,r)(mod p)
首先:1+x^(sp+q)=((1+x)^p)^s*(1+x)^q
所以:(1+x)^(sp+q)≡Σi=0…s C(s,i)x^(i*p)Σ(i=0…q)C(q,i)*x^i (利用二项式定理)
令右式i=t,j=r则右式x^(tp+r)系数为 C(s,t)*C(q,r);
对左式直接使用二项式定理
令左式i=tp+r,则左式x^(tp+r)系数为C(sp+q,tp+r);
所以得证。
关于Lucas定理的扩展:
对于模数p
1.p是素数
2.p不是素数
又可分为(1).分解完质数后每个质因子只出现一次
(2).分解完质数后每个质因子出现不止一次
3.p不是素数但p=m^t(m为素数)
处理方式:
对1 直接运用Lucas定理即可求解
对2(1) 可以运用Lucas求对p的每个质因子的模,再运用中国剩余定理将模数合并(又引出了一个flag)
对2(2) 对出现不止一次的质因子,则每个质因子的n次幂跟3一样处理,然后再运用中国剩余定理合并
对3
因为C(n,m)=n!/(m!(n-m)!)
所以我们可以分为三部分求解:n!%p^t,m!%p^t,(n-m)!%p^t 再逆元就可求解。
·求n!%p^t:
1.求p的幂,即p^(n/p) (快速幂)
2.新的阶乘 即(n/p)! (递归)
3.剩下部分 模p^t意义下以p^t为周期,所以求p^t长度就可。
剩下孤立的数长度不会超过p^t,暴力求解就可。
·关于m!%p^t和(n-m)!%(p^t)
方法大致与上述相同 但因为不互质就无法求逆元,所以应先除去质因子,求出逆元后再乘回去。
补充:
计算n!的质因子p的个数x为:
x=(n/p)+(n/(p^2))+(n/(p^3))+…
递推:f
=f[n/p]+n/p; //n/p均为向下取整
题【板】:
hdu 3037[感觉我做的题都还是挺水的]
[这道题是好久以前做的都快不记得题面了]
[也当留个板吧]
//玄学 long long #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define ll long long using namespace std; int t,n,m,p; ll exp_mod(ll a,ll b,ll p){ ll res=1; for(res;b;b>>=1,a=a*a%p){ if(b&1) res=res*a%p; } return res; } ll cmp(ll a,ll b,ll p) { if(a<b) return 0; if(a==b) return 1; if(b>a-b) b=a-b; ll ans=1,ca=1,cb=1; for(int i=0;i<b;++i) { ca=(ca*(a-i))%p; cb=(cb*(b-i))%p; } ans=(ca*exp_mod(cb,p-2,p))%p; return ans; } ll Lucas(ll n,ll m,ll p) { ll ans=1; while(n&&m&&ans) { ans=(ans*cmp(n%p,m%p,p))%p; n/=p; m/=p; } return ans; } int main(){ scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&p); printf("%d\n",Lucas(n+m,m,p)); } return 0; }
大概看了一下代码,其实就是跟Lucas的内容差不多,递归实现,但是具体实现有一些要注意的小细节而已。
【下面的内容有毒】
如果在考试的时候,出现了一道考Lucas的题目,但是已经很久没有打过Lucas了,也特别担心自己Lucas写炸,那怎么办。。
这个时候我们也可以根据组合数的计算方式暴力用求逆元水过去2333
沈阳集训Day2T1
题面:计算C(m,n) mod 9901 的值
数据范围:n<=m<=20000
【就是这么一道水题】【我还将它变得更水了23333】
【我估计整个班只有我一个人是这样做的。。。】
代码如下【每个部分都清楚易懂】:
#include<cstdio> #include<algorithm> #define ll long long using namespace std; const int mod = 9901; const int INF = 1<<30; int m,n; int tot=0; ll mul(int x,int d){ ll ans=1,xx=1; for(register int i=2;i<=x;i++){ if(d==0&&i%mod==0){ xx*=i;tot++;continue;} if(d==1&&i%mod==0){ if(tot>=1){ tot--; continue;}} ans*=i; ans%=mod; } return ans; } int inverse(ll x){ if(x==0) return 0; for(register int i=1;i<=INF;i++) if((x*i)%mod == 1) {return i;} } ll C(int m,int n){ int xx=inverse(mul(n,0)); int xxx=inverse(mul(m-n,0)); // printf("%lld %d ",mul(m-n),xxx); ll ans=((mul(m,1)%mod)*(xx%mod))%mod; return (ans%mod)*(xxx%mod)%mod; } int main(){ freopen("comb.in","r",stdin); freopen("comb.out","w",stdout); scanf("%d%d",&m,&n); printf("%lld",C(m,n)); return 0; }
在考试的时候即使觉得自己打不出来正解,也不要轻言放弃
有很多其他杂七杂八的算法
万一就水过去了呢233333
相关文章推荐