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;
} 

 

posted @ 2018-10-05 16:29  Ishtar~  阅读(161)  评论(0编辑  收藏  举报