求组合数
递推法:
C
a
b
=
C
a
−
1
b
+
C
a
−
1
b
−
1
C_a^b=C_{a-1}^b+C_{a-1}^{b-1}
Cab=Ca−1b+Ca−1b−1
一般
a
,
b
≤
2000
a,b\le2000
a,b≤2000 ,预处理时间复杂度:
O
(
n
2
)
O(n^2)
O(n2) 。
代码:
#define NUMBER1 1919
const int mod=1801;
typedef long long LL;
LL c[114][514];
inline void inint(){
for(register int i(0);i<NUMBER1;i=-~i)
for(register int j(0);j<=i;j=-~j)
if(!j)c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
逆元法(取模数为质数):
预处理时间复杂度:
O
(
n
log
n
)
O(n\log n)
O(nlogn) 。
代码:
#define NUMBER1 100000
typedef long long LL;
const int mod=1e9+7;
int fact[NUMBER1+5],infact[NUMBER1+5]
inline LL quick_mod(LL a,LL b){
LL ans(1);
while(b){
if(b&1)ans=a*ans%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
inline void inint(){
fact[0]=infact[0]=1;
for(register int i(1);i<NUMNER1;i=-~i){
fact[i]=1LL*fact[i-1]*i%mod;
infact[i]=1LL*infact[i-1]*quick_mod(i,mod-2)%mod;
}
}
signed main(){
LL ans=1LL*fact[a]*infact[b]%mod*infact[a-b]%mod;
return 0;
}
卢卡斯定理法(Lucas):
数据范围:
(
a
,
b
∈
[
1
,
1
0
18
]
,
p
∈
[
1
,
1
0
15
]
)
(a,b\in[1,10^{18}],p\in[1,10^{15}])
(a,b∈[1,1018],p∈[1,1015]) 。
原理:
C
a
b
≡
C
a
m
o
d
p
b
m
o
d
p
∗
C
a
/
p
b
/
p
(
m
o
d
p
)
C_a^b \equiv C_{a \bmod p}^{b\bmod p}* C_{a/p}^{b/p} \pmod p
Cab≡Camodpbmodp∗Ca/pb/p(modp)
查询时间复杂度:
O
(
log
p
N
+
p
log
p
)
O(\log_pN+ p\log p)
O(logpN+plogp) ,约为
4
∗
1
0
7
4* 10^7
4∗107 。
代码:
LL p;
inline LL quick_mod(LL a,LL b){
LL ans(1);
while(b){
if(b&1)ans=ans*a%p;
b>>=1,a=a*a%p;
}
return ans;
}
inline LL C(LL a,LL b){
LL ans(1);
for(register int i(1),j=a;i<=b;i=-~i,--j)
ans=ans*j%p*quick_mod(i,p-2)%p;
return ans;
}
inline LL Lucas(LL a,LL b){
if(a<p||b<p)return C(a,b);
return C(a%p,b%p)*Lucas(a/p,b/p)%p;
}
signed main(){
ans=Lucas(a,b);
return 0;
}
高精度(没有取模)
数据范围:
(
a
,
b
∈
[
1
,
5000
]
)
(a,b\in[1,5000])
(a,b∈[1,5000]) 。
思路:分解质因数,最后再乘。
时间复杂度:
b
2
b^2
b2 。
代码:
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cctype>
#define P(A) A=-~A
#define fione_i(a,b) for(register int i=a;i<=b;P(i))
#define fione_j(a,b) for(register int j=a;j<=b;P(j))
typedef long long LL;
namespace FastIo{
static char buf[100000],*p1=buf,*p2=buf,fw[100000],*pw=fw;
#define gc p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++
inline void pc(const char &ch){
if(pw-fw==100000)fwrite(fw,1,100000,stdout),pw=fw;
*pw++=ch;
}
#define fsh fwrite(fw,1,pw-fw,stdout),pw=fw
struct ubint{
int len,num[100005];
ubint(){len=0;memset(num,0,sizeof(num));}
void operator=(int a){
memset(num,0,sizeof(num));
len=0;
do{
num[++len]=a%10;
a/=10;
}while(a);
}
ubint operator*(int a)const{
ubint res;
res.len=len;
fione_i(1,res.len){
res.num[i]+=a*num[i];
res.num[i+1]=res.num[i]/10;
res.num[i]%=10;
}
while(res.num[res.len+1]){
P(res.len);
res.num[res.len+1]+=res.num[res.len]/10;
res.num[res.len]%=10;
}
return res;
}
};
struct QIO{
char ch;
inline void read(int &x){
x=0,ch=gc;
while(!isdigit(ch))ch=gc;
while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=gc;}
}
inline void write(ubint a){while(a.len)pc(a.num[a.len--]^48);}
}qrw;
}
using namespace FastIo;
#define NUMBER1 5000
int prime[NUMBER1+5],cnt(0),sum[NUMBER1+5];
bool st[NUMBER1+5];
inline int get(int n,int p){
int ans(0);
while(n){
ans+=n/p;
n/=p;
}
return ans;
}
inline void PRIME(){
fione_i(2,NUMBER1){
if(!st[i])prime[++cnt]=i;
for(register int j(1);prime[j]*i<=NUMBER1;P(j)){
st[prime[j]*i]=true;
if(!(i%prime[j]))break;
}
}
}
ubint ans;
signed main(){
PRIME();
int a,b;
ans=1;
qrw.read(a);
qrw.read(b);
fione_i(1,cnt)sum[i]=get(a,prime[i])-get(a-b,prime[i])-get(b,prime[i]);
fione_i(1,cnt)
while(sum[i]--)ans=ans*prime[i];
qrw.write(ans);
fsh;
exit(0);
return 0;
}