Lucas定理(求組合數取模) 擴充套件Lucas定理(解決模數非質情況)
在比賽時 , 如果遇到的n比較大 , 我們不能通過預處理階乘和逆元來計算 , 而題目又要求對答案取一個質數模的時候 , 我們可以用Lucas定理來簡化計算
Lucas 定理:
定義 : n,m是非負整數,p是素數時 ,
公式 :
程式碼 :
LL Lucas(LL n,LL m){
if(m==0)return 1ll;
return C(n%mod ,m%mod)*Lucas(n/mod,m/mod)%mod;
}
擴充套件Lucas定理:
擴充套件Lucas定理用於解決模數非質數時的情況
懶得敲了,直接手寫上圖好了(好久沒寫作業不會寫字了多多包涵)
也就是說 , 我們對於模數M , 在非質數的時候 , 把它分成多個兩兩互質的數(按照質因子分解一定保證兩兩互質) , 求出 , 然後把多組求CRT就是答案
接下來要解決的是 C實際上的三個階乘的乘除 , 所以當下解決的就變成了 假設為 1. 後半部分也是階乘 , 直接重新遞迴即可 2. 前半部分中 , 有一個迴圈節 , , 對於後面的零頭暴力就行了 3. 對於中間p的此法 , 記錄一下數量 , 最後三個階乘的數量相加減即可 |
模板 :
#include<bits/stdc++.h>
using namespace std;
#define i64 long long
i64 POW(i64 a,i64 b,i64 mod)
{
i64 ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
i64 POW(i64 a,i64 b)
{
i64 ans=1;
while(b)
{
if(b&1) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
i64 exGcd(i64 a,i64 b,i64 &x,i64 &y)
{
i64 t,d;
if(!b)
{
x=1;
y=0;
return a;
}
d=exGcd(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
return d;
}
bool modular(i64 a[],i64 m[],i64 k)
{
i64 d,t,c,x,y,i;
for(i=2;i<=k;i++)
{
d=exGcd(m[1],m[i],x,y);
c=a[i]-a[1];
if(c%d) return false;
t=m[i]/d;
x=(c/d*x%t+t)%t;
a[1]=m[1]*x+a[1];
m[1]=m[1]*m[i]/d;
}
return true;
}
i64 reverse(i64 a,i64 b)
{
i64 x,y;
exGcd(a,b,x,y);
return (x%b+b)%b;
}
i64 C(i64 n,i64 m,i64 mod)
{
if(m>n) return 0;
i64 ans=1,i,a,b;
for(i=1;i<=m;i++)
{
a=(n+1-i)%mod;
b=reverse(i%mod,mod);
ans=ans*a%mod*b%mod;
}
return ans;
}
i64 C1(i64 n,i64 m,i64 mod)
{
if(m==0) return 1;
return C(n%mod,m%mod,mod)*C1(n/mod,m/mod,mod)%mod;
}
i64 cal(i64 n,i64 p,i64 t)
{
if(!n) return 1;
i64 x=POW(p,t),i,y=n/x,temp=1;
for(i=1;i<=x;i++) if(i%p) temp=temp*i%x;
i64 ans=POW(temp,y,x);
for(i=y*x+1;i<=n;i++) if(i%p) ans=ans*i%x;
return ans*cal(n/p,p,t)%x;
}
i64 C2(i64 n,i64 m,i64 p,i64 t)
{
i64 x=POW(p,t);
i64 a,b,c,ap=0,bp=0,cp=0,temp;
for(temp=n;temp;temp/=p) ap+=temp/p;
for(temp=m;temp;temp/=p) bp+=temp/p;
for(temp=n-m;temp;temp/=p) cp+=temp/p;
ap=ap-bp-cp;
i64 ans=POW(p,ap,x);
a=cal(n,p,t);
b=cal(m,p,t);
c=cal(n-m,p,t);
ans=ans*a%x*reverse(b,x)%x*reverse(c,x)%x;
return ans;
}
//計算C(n,m)%mod
i64 Lucas(i64 n,i64 m,i64 mod)
{
i64 i,t,cnt=0;
i64 A[205],M[205];
for(i=2;i*i<=mod;i++) if(mod%i==0)
{
t=0;
while(mod%i==0)
{
t++;
mod/=i;
}
M[++cnt]=POW(i,t);
if(t==1) A[cnt]=C1(n,m,i);
else A[cnt]=C2(n,m,i,t);
}
if(mod>1)
{
M[++cnt]=mod;
A[cnt]=C1(n,m,mod);
}
modular(A,M,cnt);
return A[1];
}
int main(){
i64 n,m,mod;
while(scanf("%lld%lld%lld",&n,&m,&mod))
printf("%lld\n",Lucas(n,m,mod));
}
相關推薦
Lucas定理(求組合數取模) 擴充套件Lucas定理(解決模數非質情況)
在比賽時 , 如果遇到CmnCnm的n比較大 , 我們不能通過預處理階乘和逆元來計算 , 而題目又要求對答案取一個質數模的時候 , 我們可以用Lucas定理來簡化計算 Lucas 定理: 定義 : n,m是非負整數,p是素數時 , Lucas(
求組合數取模(楊輝三角打表 & 求逆元(擴充套件歐幾里得、費馬小定理、尤拉定理、線性求法) & Lucas)
在acm競賽中,組合數取模的題目還是經常會見到的,所以這是有必要掌握的一個演算法。我本人就因為這個東西而被坑了很多次了= =之前的部落格也都扯過了,就不多說了,下面進入正題。 (1)楊輝三角求組合數 楊輝三角這個東西應該都不陌生,三角的兩邊始終為一,之後向
Lucas定理及組合數取模
引入 楊輝三角 std 數據 組合數取模 有關 ans main include 引入: 組合數C(m,n)表示在m個不同的元素中取出n個元素(不要求有序),產生的方案數。定義式:C(m,n)=m!/(n!*(m-n)!)(並不會使用LaTex QAQ)。 根據題目中對組合
Lucas定理 大組合數取模
對於C(n, m) mod p。這裡的n,m,p(p為素數)都很大的情況。就不能再用C(n, m) = C(n - 1,m) + C(n - 1, m - 1)的公式遞推了。 這裡用到Lusac定理 For non-negative integers m and n and a prime p, the f
Lucas定理——大組合數取模
大組合數取模,求C[n][m]%p 公式:C[n][m]%p == C[n%p][m%p]*C[n/p][m/p]%p 注意,Lucas的要求是n,m<=10^5,如果n,m>=10^5,那麼要求p<=10^5 楊輝三角: f[0][
Lucas定理求組合數模板
end code == turn tdi div rac bsp 模板 $Lucas(n,m,p)=C(n\%p,m\%p)*Lucas(n/p,m/p,p)$ $C^n_m=\frac{n!}{m!(n-m)!}$ $x^{p-1}\equiv 1(mod p)\Long
Lucas定理求組合數
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm>
組合數取模&&Lucas定理題集
pac 假設 次方 href ace 範圍 統一 lucas定理 != 題集鏈接: https://cn.vjudge.net/contest/231988 解題之前請先了解組合數取模和Lucas定理 A : FZU-2020 輸出組合數C(n, m) mod p (
組合數取模(楊輝三角+Lucas定理+模合數)
/* (1) 1 <= m <= n <= 1000 和 1 <= p <= 10^9 ( p可以是任何數 ) 這個問題比較簡單,組合數的計算可以靠 楊輝
Lucas定理應用分析——大組合數取模
首先給出Lucas(盧卡斯)定理: 有非負整數A、B,和素數p,A、B寫成p進製為:A=a[n]a[n-1]...a[0],B=b[n]b[n-1]...b[0]。 則組合數C(A,B)與C(a[n],b[n])×C(a[n-1],b[n-1])×...×C
hdu5968(組合數取模Lucas定理)
瞬間移動 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Sub
3037 Saving Beans (數論,組合數取模,lucas定理)
也是通過看別人的程式碼才知道這個題應該怎麼做:Lucas定理題目相當於求n個數的和不超過m的方案數。如果和恰好等於m,那麼就等價於方程x1+x2+...+xn = m的解的個數,利用插板法可以得到方案數為:(m+1)*(m+2)...(m+n-1) = C(m+n-1,n-1) = C(m+n-1,m)現在
hdu-3037-組合數取模-Lucas定理
http://acm.hdu.edu.cn/showproblem.php?pid=3037 題意很簡單 求C(n+m,m)%p,P是小於1e5的素數 n,m《1e18 那麼得到
hdu3037 lucas 定理 組合數取模
#include<stdio.h> #include<string> #include<map> #include<vector> #include&l
hdu 3037 費馬小定理+逆元求組合數+Lucas定理
void log 打表 數學 mod turn ret iostream toc 組合數學推推推最後,推得要求C(n+m,m)%p 其中n,m小於10^9,p小於1^5 用Lucas定理求(Lucas定理求nm較大時的組合數) 因為p數據較小可以直接階乘打表求逆元
組合數取模1:盧卡斯定理
模板: #include<iostream> #include<algorithm> #include<cstdio> #define ll long long #define N 100005 using namespace std; int k,n,m
求組合數以及組合數取模
1、採用C(a, b) = n! / (m! * (n - m)!),適用範圍為n <= 20 typedef long long ll; const int maxn=20+5; ll a[maxn]; void init() { a[0]=1; for(int i=1; i&l
[演算法 18_001] Lucas 定理與大組合數取餘
Lucas 定理 該定理是用來求當 (nm) ( n m
簡單求組合數(除法取模)
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f const int maxn=1e5+9; #define LL long long int e_gcd(int a,int b
各種逆元求法 組合數取模 comb (組合數 Lucas)
組合數取模(comb) 【問題描述】 計算C(m,n)mod 9901的值 【輸入格式】 從檔案comb.in中輸入資料。 輸入的第一行包含兩個整數,m和n 【輸出格式】 輸出到檔案comb.out中。 輸出一行,一個整數 【樣例輸入】 2