简化版题意:
给定n,m(n<=m),求C(n,m)的末尾有几个0
输入格式:
第一行一个整数t,代表数据组数。
接下来t行,每行两个整数n,m
输出格式:
t行,每行一个整数,代表C(n,m)的末尾0的个数。
样例输入:
3
10 1
11 7
20 4
样例输出:
1
1
0
数据范围:
1<=m<=n<=1000000,t<=1000
首先这道题需要知道一个公式:C(n,m)=n!/(n-m)!*m!
然后10=2*5,也就是说,对于一个数,我们将其因数分解,2和5中较少的数的个数,就是该数末尾0的个数。
于是对于每一组数据,暴力算出上下两式中2和5的个数,然后上下因为是除的关系,所以可以相互抵消,于是上下的数中2的个数和5的个数中较少的就是0的个数了。
吐槽一句:题解中说,要用前缀和,但是我并没有写任何与前缀和相关的代码,但是还是A了。
再加一句:对于一个数的阶乘,2的个数一定是比5多的,所以这个题其实只需要输出5的个数就好了。。。比较大小只是保险而已。
#include<cstdio> void read(int &y) { y=0;char x=getchar(); while(x<‘0‘||x>‘9‘) x=getchar(); while(x>=‘0‘&&x<=‘9‘) { y=y*10+x-‘0‘; x=getchar(); } } int solve2(int x) { int s=0; while(x/2!=0) { s+=x/2; x/=2; } return s; } int solve5(int x) { int s=0; while(x/5!=0) { s+=x/5; x/=5; } return s; } int min(int x,int y) { return x<y ? x : y; } int t,m,n; int main() { read(t); while(t--) { read(m),read(n); int x=solve2(m)-(solve2(n)+solve2(m-n)); int y=solve5(m)-(solve5(n)+solve5(m-n)); printf("%d\n",min(x,y)); } return 0; }
时间: 2024-10-03 13:21:11