1. 程式人生 > >NOIP模擬 階乘(質因數分解+二分答案)

NOIP模擬 階乘(質因數分解+二分答案)

【題目描述】

有n個正整數a[i],設它們乘積為p,你可以給p乘上一個正整數q,使p*q剛好為正整數m的階乘,求m的最小值。

【輸入格式】

共兩行。

第一行一個正整數n。

第二行n個正整數a[i]。

【輸出格式】

共一行

一個正整數m。

【樣例輸入】

1

6

【樣例輸出】

3

【備註】

對於10%的資料,n<=10

對於30%的資料,n<=1000

對於100%的資料,n<=100000,a[i]<=100000

【題目分析】

這是第幾次被二分答案上界給neng死了。。。10分滾粗。。。

首先可以先將p分解質因數,可以推出最後m!一定是包含了p的所有質因子的。

所以就可以二分m的值(上界要設很大,否則如果出現100000個相同數(或類似這種情況),最後m值就會很大),判斷一下是否包含p,如果可以就下調,否則上調。

【程式碼~】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn=100010;

LL P[maxn],s1[maxn],s2[maxn];
LL tot,n,a,last;
bitset<maxn> isprime;

void pre()
{
	isprime[0]=isprime[1]=1;
	for(LL i=2;i<=100000;++i)
	{
		if(!isprime[i])
		{
			for(LL j=i+i;j<=maxn;j+=i) 
			  isprime[j]=1;
			P[++tot]=i;
		}
	}
}

LL check(LL x)
{
	memset(s2,0,sizeof(s2));
	for(LL i=1;P[i]<=x&&i<=tot;++i)
	{
		LL tmp=x;
		while(tmp)
		{
			tmp/=P[i];
			s2[i]+=tmp;
		}
	}
	for(LL i=1;i<=last;++i)
		if(s1[i]>s2[i]) 
		  return false;
	return true;
}

void fj(LL x)
{
	if(x==1||x==0) 
	  return;
	for(LL i=1;P[i]<=x&&i<=tot;++i)
	{
		while(x%P[i]==0)
		{
			x/=P[i];
			s1[i]++;
		}
		last=max(last,i);
	}
}

int main()
{
	pre();
	scanf("%lld",&n);
	for(LL i=1;i<=n;++i)
	{
		scanf("%lld",&a);
		fj(a);
	}
	LL l=1,r=100000000000;
	while(l<r)
	{
		LL mid=l+r>>1;
		if(check(mid)) 
		  r=mid;
		else 
		  l=mid+1;
	}
	printf("%lld",l);
	return 0;
}