题目大意:输入n,m。求n!在m进制中末尾有几个零,以及为几位数。

解题思路:林炜大佬打得代码。。。漂亮。n!在m进制有几位,卡精度,用斯特林公式wa了。用对数求,加上1e-9才过。对数求法是这样的。。。设结果为X位数,那么n!< m^X。所以X = logm(n!) = logm (2) + ...logm(n)。而末尾0的求法,是求出m的质因数,然后算2~n,能被不同的m质因数整除的为质因数的几倍,取最少的,则为末尾的0。例如:5 16。16 = 2 * 2 * 2 * 2。2~5只有2、4可以被2整除,一共3个2。要求4个2才能一个0。所以末尾没有0。

ac代码:

#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
int n, k, cnt, num, m;
int vis[2000005], mark[2000005];
double zero;
int main()
{
while (scanf("%d%d", &n, &k)!=EOF){
memset(vis, 0, sizeof(vis));
memset(mark, 0, sizeof(mark));
zero = 0;
if ( !n || n == 1)
zero = 1;
else{
for (int i = 2; i <= n; i++)
zero += log(i);
zero = floor( zero/log(k) + 1e-9 ) + 1;
}
m = k;
for(int i = 2; i <= k; i++)
while(k%i==0){
vis[i]++;
k /= i;
}
for(int i = 2; i <= n; i++){
int d =sqrt(i);
int s = i;
for(int j = 2; j <= d; j++)
while(s % j==0){
mark[j]++;
s/=j;
}
mark[s]++;
}
int cnt = 99999999;
for(int i = 1; i <= m; i++)
if(vis[i])
cnt = min(mark[i]/vis[i],cnt);
printf("%d %.0lf\n", cnt, zero);
}
return 0;
}

大佬手打质数表,存一份:

for(int i = 2; i <= 800; i++)
if(!p[i]){
p[++p[0]] = i;
for(int j = 2*i; j <= 800; j+=i)
p[j] = 1;
}