题目来源
https://www.luogu.org/problem/show?pid=3927
题目描述
银桑、神乐、新八三人在测试阿姆斯特朗回旋加速喷气式阿姆斯特朗炮的威力。 阿姆斯特朗回旋加速喷气式阿姆斯特朗炮十分神奇,使用方式如下:
输入两个数字n,k到阿姆斯特朗回旋加速喷气式阿姆斯特朗炮的控制台中,然后阿姆斯特朗回旋加速喷气式阿姆斯特朗炮会计算出n!并把它转化为k进制。
最后n!在k进制下末尾0的个数就是本次发射的威力,每个0代表1点威力。 为了测试时不造成太大的破坏,三人想知道每次测试,发射的威力有多大。
现在给出多组测试的n和k,请计算出每次发射的威力。输入描述 输入文件为amstl.in 题目包含多组数据,以EOF(文件结尾)为结束。 对于每组数据,输入一行两个正整数n,k;
输出描述 输出文件为amstl.out 每组数据一行,包含一个整数,表示本次发射的威力。
样例输入
10 40
样例输出
2数据范围:
对于 30%的数据, n <= 1000000, k = 10
对于另外 10%的数据, n <= 20, k <= 20
对于另外 20%的数据, n <= 50, k <= 52
对于另外 10%的数据, n<=10^12, k = 2
对于 100%的数据, n <= 10^12, k <= 10^12
题目解释:求 n!在 k 进制下末尾 0 的个数
正解:这个题求n!在k进制下末尾0的个数,其实就是求在n!中%k=0出现的情况。首先这个数据范围很大所以我们考虑对N!,k进行质因数分解。分解N!利用原来说过的
f(α)=n/α+n/α^2+…+n/α^k (α^k<=n)这个式子全是下取整,复杂度大约是logN。枚举2~根号k,对于k的每个质数,我们都统计出在k中的出现次数,再利用上面讲的思想,logN求出N!中的个数,相除就是这个因子出现的0的个数,然后每次都取min,得到最优的答案。(正确性:类似于木桶原理,也就是决定0的个数出现的次数,只取决于答案最小的因子,因为大小因子都有才能组合成k)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const long long maxn=1e16+8;
int main()
{
long long ans;
long long n,k,cnt1,cnt2;
while(scanf("%lld%lld",&n,&k)!=EOF)
{
ans=maxn;
long long shu=sqrt(k)+1;
for(int i=2;i<=shu;i++)
{
cnt1=0,cnt2=0;
while(k%i==0){
cnt1++;
k/=i;
}
if(cnt1==0) continue;
long long q=i;
while(q<=n)
{
cnt2+=(n/q);
q*=i;
}
ans=min(ans,cnt2/cnt1);
}
cnt2=0;
if(k>1)
{
long long q=k;
while(q<=n)
{
cnt2+=(n/q);
q*=k;
}
ans=min(ans,cnt2);
}
if(ans==maxn) ans=0;
printf("%lld\n",ans);
}
return 0;
}