*PS:一次胡策的题,改成了多组数据,所以代码也是多组数据的qwq
题目背景
SOL君(炉石主播)和SOL菌(完美信息教室讲师)是好朋友。
题目描述
SOL君很喜欢阶乘。而SOL菌很喜欢研究进制。
这一天,SOL君跟SOL菌炫技,随口算出了n的阶乘。
SOL菌表示不服,立刻就要算这个数在k进制表示下末尾0的个数。
但是SOL菌太菜了于是请你帮忙。
输入输出格式
输入格式:
每组输入仅包含一行:两个整数n,k。
输出格式:
输出一个整数:n!在k进制下后缀0的个数。
输入输出样例
输入样例#1:
10 40
输出样例#1:
2
说明
对于20%的数据,n <= 1000000, k = 10
对于另外20%的数据,n <= 20, k <= 36
对于100%的数据,n <= 10^12,k <= 10^12
update
1.一组数据
2.K不会==1
3.现在std没有爆long long
4.对数据有问题联系icy (建议大家不要面向数据编程)
如何求一个数在k进制下末尾0的个数。
我们发现,10进制下,2*5–> 1个末尾0 ; 2进制下 ,2 –>1个末尾0。那么求一个数在k进制下末尾零的个数即把k进行质因数分解,同时找出这个数中所包含的各个因子的个数(如果需要3个2 则3个2记作1个) 取min。
问题转化为k的质因数分解和如何快速统计n!中的k的因子个数。
问题1:k的质因数分解
从1 for 到 sqrt(n),对于每个因子i都是一直除到不能除为止,所以并不需要先进行素数筛(之前的因子已经完全除尽了)。
代码|ω・`)
void Done(long long x)
{
Cnt=0;
for(long long i=2;i<=sqrt(K);++i)
{
if(x%i==0) P[++Cnt].name=i,P[Cnt].cnt=0;
while(x%i==0)
{
++P[Cnt].cnt;
x/=i;
}
if(x==1||i>x) break;
}
if(x!=1) P[++Cnt]=(maple){x,1};
}
问题2:快速求1~n中某一因子个数之和。
对于 a^k < =n < a ^k+1
如 在1~9 中求因子2的个数之和
1 2 3 4 5 6 7 8 9
发现: 除以
2^1 1 1 1 1
2^2 1 1
2^3 1
共有 2^3/2^1+2^3/2^2+2^3/2^3个。
故 1~n中因子a的个数之和为:
a^k/a^1+a^k/a^2+a^k/a^3+…+a^k/a^k
因为计算机会自动下取整 故 1~n中因子a的个数为
n/a^1+n/a^2+n/a^3+…+n/a^k
代码|ω・`)
int A=a;
while(A<=N)
{
Ans+=N/A;
A*=a;
}
这道题的代码|・ω・`)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
long long N,K,ans,cnt,Cnt;
struct maple{
long long name,cnt;
}P[10000000];
void Done(long long x)
{
Cnt=0;
for(long long i=2;i<=sqrt(K);++i)
{
if(x%i==0) P[++Cnt].name=i,P[Cnt].cnt=0;
while(x%i==0)
{
++P[Cnt].cnt;
x/=i;
}
if(x==1||i>x) break;
}
if(x!=1) P[++Cnt]=(maple){x,1};
}
int main()
{
while(scanf("%lld%lld",&N,&K)!=EOF)
{
ans=1e16+7;
Done(K);
for(long long i=1;i<=Cnt;++i)
{
long long A=P[i].name,a=P[i].name,Ans=0;
while(a<=N)
{
Ans+=N/a;
a*=A;
}
Ans/=P[i].cnt;
ans=min(ans,Ans);
}
printf("%lld\n",ans);
}
return 0;
}