GDKOI2014「阶乘」

题目

Description
新学期第一节数学课,老师给同学们介绍一个新知识一一阶乘。“自然数n的阶乘,是所有小于等于n的正整数的乘积,写作n!。也就是说1×2×3×…×n。特别地,0!=1。”喜欢上数学课的壕壕听得津津有味,一边听一边计算着每个自然数的阶乘。壕壕在计算的时候发现,基本上每个数的阶乘都是以若千个零结尾的数学老师知道了壕壕的发现后,给了壕壕一道思考题:“对于一个自然数n,它的阶乘在base进制下的表示中,以多少个零结尾呢?比如说10!,在十进制的表示下是以两个零结尾的3628800,但在二进制的表示下是以八个零结尾的110111010111000这个问题把壕壕难倒了。作为全班最聪明机智的同学,同时也是壕壕同桌的你也听到了老师的思考题。你能比壕壕更快想到这道思考题吗?

Sample Input

2
10 10 
10 2

Sample Output

2
8

思路

n!n!basebase 进制下结尾有 xx00,那么 n!n! 一定可以表示为 basex×ybase^x\times y
由于数据较大,故对 basebase 分解质因数,再对其质因子分别计算贡献。
当然,暴力求贡献是不可取的。
比如说求 11nn 有几个 22,从 11 枚举到 nn 求找会 TLE。
于是可以让 nn 一直除以 22,把每次的商累加起来,即为 11nn22 的个数。其他质数同理。


#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define re register
using namespace std;

typedef long long ll;
const int maxn=10005;
int T;
ll n, base;
ll prime[maxn], cnt[maxn];
int main() {
	scanf("%d", &T);
	while (T--) {
		int tot (0);
		scanf("%lld %lld", &n, &base);
		
		ll temp=base;
		memset(cnt, 0, sizeof cnt);
		for (re int i=2; i<=floor(sqrt(base)); i++) {
			if (temp==1) break;
			if (temp%i==0) {
				prime[++tot]=i;
				while (temp%i==0) {
					temp/=i;
					cnt[tot]++;
				}
			}
		}
		if (temp-1) {
			prime[++tot]=temp;
			cnt[tot]=1;
		}
		
		ll ans (0xFFFFFFFFFFFFFF);
		for (re int i=1; i<=tot; i++) {
			ll sum (0), temp (n);
			while (temp>=prime[i]) {
				temp/=prime[i];
				sum+=temp;
			}
			ans=min(ans, sum/cnt[i]);
		}
		
		printf("%lld\n", ans);
	}
	
	return 0;
}
posted @ 2020-08-13 20:35  willbe233  阅读(81)  评论(0)    收藏  举报