2018.10.05【校内模拟】阶乘(唯一分解)(二分答案)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82947878

【问题描述】

有 n 个正整数 a[i],设它们乘积为 p,你可以给 p 乘上一个正整数 q,使 p*q 刚好为正
整数 m的阶乘,求 m的最小值。

【输入】

共两行。
第一行一个正整数 n。
第二行 n个正整数 a[i]。

【输出】

共一行
一个正整数 m。

【输入样例】

1 6

【输出样例】

3
样例解释:
当 p=6, q=1 时, p*q=3!

【数据范围与约定】

对于 10%的数据, n<=10
对于 30%的数据, n<=1000
对于 100%的数据, n<=100000, a[i]<=100000


解析:

直接把一个数分解质因数,把结果存起来。

显然, n ! n! 中含有的各个质因数个数是单调不减的,所以这道题可以二分答案。
根据木桶原理,我们要令所有的质因数个数都能满足,这是check的依据。

那么怎么统计 n ! n! 中有多少个某种质因数呢?

就像统计位数一样统计就行了。

显然, n ! n! 中质数 p p 的次数是 i = 1 n p \sum_{i=1}^{\infty}\lfloor\frac{n}{p}\rfloor ,直接统计即可。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
ll getint(){
	re ll num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

inline
void outint(ll a){
	static char ch[23];
	if(a==0)pc('0');
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

cs int P=100005;
bitset<P> mark;
int prime[P],pcnt;

inline
void linear_sieves(int len=P-5){
	for(int re i=2;i<=len;++i){
		if(!mark[i])prime[++pcnt]=i;
		for(int re j=1;j<=pcnt&&i*prime[j]<=len;++j){
			mark[i*prime[j]]=true;
			if(i%prime[j]==0)break;
		}
	}
}

int cnt[P];
int maxp;

inline
int div(int a){
	for(int re i=1;i<=pcnt&&a>1;++i){
		if(a==a/prime[i]*prime[i])maxp=max(maxp,i);
		while(a==a/prime[i]*prime[i])a/=prime[i],++cnt[prime[i]];
	}
}

inline
bool check(int x){
	for(int re i=1;i<=maxp;++i){
		int cont=0;
		for(ll k=prime[i];k<=x&&cont<cnt[prime[i]];k*=prime[i])cont+=x/k;
		if(cont<cnt[prime[i]])return false;
	}
	return true;
}

int n;
signed main(){
	linear_sieves();
	n=getint();
	for(int re i=1;i<=n;++i){
		int x=getint();
		div(x);
	}
	int l=1,r=100000000;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	outint(l);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/82947878