小A的组合数

小A的组合数

题目描述

\(C_n^m\)表示组合,组合公式为:\(C_n^m=\frac{n!}{m!\times (n-m)!}\),请你求出\(C_n^m\)的因子个数\(tot\),由于大难会很大,请你输出的答案模上一个大数\(mod=10^9+7+cnt\)\(cnt\)表示\(n!\)末尾\(0\)的个数。

题目解析

约数(因子)个数函数:

\[n=p^{k_1}_1p_2^{k_2}...p^{k_n}_n \\ \tau (n)=(k_1+1)(k_2+1)(k_3+1)...(k_n+1) \]

我们可以得到:

\(k_1=\frac{n}{p_1}+\frac{n}{p_1^2}+\frac{n}{p_1^3}+....+\frac{n}{p_1^j}\)

\(k_2=\frac{n}{p_2}+\frac{n}{p_2^2}+\frac{n}{p_2^3}+....+\frac{n}{p_2^j}\)

\(k_3=\frac{n}{p_3}+\frac{n}{p_3^2}+\frac{n}{p_3^3}+....+\frac{n}{p_3^j}\)

但是由于本题是分数,所以求出来的\(k\)还要减去\(m,n-m\)里面的\(k\)

接下来就是求出\(n!\)有最后有多少个零:

易得,\(10\)是由\(2*5\)得到的

由于阶乘中\(2\)一定比\(5\)多,所以我们仅需算出\(5^k\)中的\(k\)即可,接下来就和上面思路差不多了。

CODE

#include<bits/stdc++.h>
#define ll __int128
using namespace std;
const int maxn = 2e6+43;
inline ll read_int(){
	ll a=0;bool f=0;char g=getchar();
	while(g<'0'||'9'<g) {if(g=='-') f=1;g=getchar();}
	while('0'<=g&&g<='9') a=a*10+g-'0',g=getchar();
	return f ? -a : a;
}

inline void write(ll a,bool b=1){
	char lin[30];int top=0;
	if(a<0) a=-a,putchar('-');
	while(a){
		lin[++top]=a%10+'0';
		a/=10;
	}
	if(!top) lin[++top]='0';
	while(top) putchar(lin[top--]);
	if(b) putchar('\n');
}

ll wu[100]={0,5,25,125,625,3125,15625,78125,390625,1953125,9765625};
int go=11;
ll mod=1e9+7,MOD;

ll top=0,prime[maxn];
bool no[maxn];
inline void Prime(){
	for(ll i=2;i<=2e6;i++){
		if(!no[i]) prime[++top]=i;
		for(ll e=1;e<=top&&prime[e]*i<=2e6;e++){
			no[prime[e]*i]=1;
			if(i%prime[e]==0) break;
		}
	}
}

inline void read(){
	ll n=read_int(),m=read_int();
	ll cnt=0;
	for(int i=1;i<=10;i++) cnt+=n/wu[i];
//	cout<<cnt<<endl;
	MOD=mod+cnt;
	ll N=n,M1=m,M2=n-m;
	ll ans=1;
	for(int i=1;i<=top&&prime[i]<=n;i++){
		ll k=0,jl=1;
		for(int e=1;jl<=n;e++){
			jl*=prime[i];
			k=k+(N/jl-M1/jl-M2/jl);
		}
//		cout<<prime[i]<<" "<<k<<endl;
		ans=ans*(k+1)%MOD;
	}
	write(ans);
}

int main (){
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
	Prime();
	int T=read_int();
	while(T--) read();
}

posted @ 2022-08-09 16:38  轩Demonmaster  阅读(82)  评论(5)    收藏  举报