中石油训练赛 - 小A进学校(唯一分解定理)

题目链接:点击查看

题目大意:求k进制n的阶乘下末尾0的个数

题目分析:之前接触过10进制下求n的阶乘末尾0的个数,当时只知道需要求5出现的个数,但并不知道原理,公式是这样的:

int ans=0;
while(n)
{
    ans+=n/5;
    n/=5;
}

也没有去分析过原理,然后这道题目就要涉及到原理了,我们如果想要求末尾出现0,那么在k进制下就要尽可能多的出现k的幂,也就是k*k*……*k,让其中的k的数量尽可能多,那么我们需要对k进行唯一分解,求出所有因子,然后对于每个因子都进行上述公式尝试求结果,求出来的结果代表的是当前因子对于求尽可能多的k所做的贡献,因为每个因子出现的次数不一定是一次,所以需要用这个结果再除以出现的次数,计算每个因子出现的频率,最后选出最小值即可,证明的话我不太会证,所以很简单的一道数论题不看别的大佬的思路真的做不出来。。

上代码吧:

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<unordered_map>
using namespace std;
   
typedef long long LL;
  
const int inf=0x3f3f3f3f;
  
const int N=1e6+100;

bool book[N];

int pri[N];

int cnt=0;

unordered_map<int,int>mp;

void P()//欧拉筛 
{
    for(int i=2;i<N;i++)
    {
    	if(!book[i])
    		pri[cnt++]=i;
    	for(int j=0;j<cnt&&pri[j]*i<N;j++)
    	{
    		book[pri[j]*i]=true;
    		if(i%pri[j]==0)
    			break;
	}
    }
}

LL getnum(LL a,LL b)//求该质因子a在b中做出的贡献
{
	LL ans=0;
	while(b)
	{
		ans+=b/a;
		b/=a;
	}
	return ans;
}
 
int main()
{
    P();
    LL n,k;
    cin>>n>>k;
    for(int i=0;i<cnt&&pri[i]<=sqrt(double(k));i++)//对k唯一分解 
    {
    	while(k%pri[i]==0)
    	{
    		k/=pri[i];
    		mp[pri[i]]++;//mp维护每个质因子出现的次数
	}
	if(k==1)
		break;
    }
    LL ans=1e18;
    if(k!=1)//如果最后k还不为1,说明k为一个很大的质数,特判一下
    	ans=min(ans,getnum(k,n));
    for(auto it:mp)//it.first代表质因子,it.second代表质因子出现的次数
    {
    	ans=min(ans,getnum(it.first,n)/it.second);
    }
    cout<<ans<<endl;
   
   
   
   
   
   
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值