CF538div2-C-Trailing Loves (or L'oeufs?)-数论

题目传送门
题意:
给你n<=1e18,k<=1e12,求n!(n的阶乘)转化为k进制后,有多少个后导0.
思路:
问题转化为求n%(k^r) == 0的r的最大值。
由于自己叙述太麻烦,就将官方题解贴出来。
The problem can be reduced to the following: finding the maximum r that n ! is divisible by br.

By prime factorization, we will have the following: b = p1y1·p2y2·…·pmym.

In a similar manner, we will also have: n ! = p1x1·p2x2·…·pmxm·Q (with Q being coprime to any pi presented above).

The process of finding p1, p2, …, pn, y1, y2, …, ym can be done by normal prime factorization of the value b.

The process of finding x1, x2, …, xm is a little bit more tricky since the integer they were originated (n !) is too huge to be factorized manually. Still the factorial properties gave us another approach: for each pi, we can do the following:

Initially, denote xi = 0.

Repeatedly do the following: add to xi, then divide n by pi. The loop ends when n is zero.

After all, we can obtain the final value r as of following: .

Total complexity: (as the number of prime factors of an integer b will not surpass ).

这个题解还好看懂,的那就是有一个地方有点难理解。如何处理n!,将n!表示成pi^xi中的xi求出来,其中我们只关注k分解出来的质因数,然后在此基础上处理n!,求出xi.边分解k边处理n!节约空间。
那么如何理解下面的代码可以求出xi是关键。
在这里插入图片描述
下面举个例子:
n = 125,i = 5;
首先将1-125之间可以整除5的数写出来,并标记每个数包含了几个5.
5(1) 10(1) 15(1) 20(1) 25(2) … 50(2) 75(2) … 95(1)…100(2) 125(3)
首先将c/i = 25;表示1-125之间有25个数包含了1个5,然后将c/=i;c = 25;然后c /5 = 5;表示有5个数包含了2个5,之后就是1个数包含了3个5(125)。
这个过程就像一层一层地求。如下:
5
5 5 5…5 5
5 5 5 5 5… 5 5 5… 5
那么第一列表示125。
求他的例子比如124也是一样的。

这个理解,问题就迎刃而解了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<cstring>
#include<string>
#include<cmath>

using namespace std;

typedef long long LL;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i = a;i <= b;++i)
#define rep(i,a,b) for(int i = a;i >= b;--i)
const int maxn = 3e5;
LL n = 0,b = 0; 

int main(){

	//std::ios::sync_with_stdio(false);
	
	while(~scanf("%I64d %I64d",&n,&b)){
		LL ans = 1000000000000000000LL;
				
		//per(i,2,b){//变分解质因数,边处理,节约空间 
		for(LL i = 2;i <= b;++i){//变分解质因数,边处理,节约空间 
			if(1ll*i*i > b){//说明b是质数 
				i = b; 
			}
			int cnt = 0;
			while(b % i == 0){
				b /= i;
				++cnt;
			}
			if(cnt == 0){
				continue;
			}
			LL tmp = 0,mul = 1;
			/*
			while(mul <= n/i){//不是mul <= n是为了防止mul超过longlong 
				mul *= i; 
				tmp += (n/mul);
				
			}
			*/
			LL c = n;
			while(c > 0){//还不如这样直接 
				tmp += (c/i);
				c /= i;
			}
			ans = min(ans,tmp / cnt);
		}
		printf("%I64d\n",ans);
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值